> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.termina.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.termina.ai/_mcp/server.

# Concentration

GET https://app.termina.ai/api/v1/group/{group_id}/deal/{deal_id}/data/concentration

Get the product concentration for the company associated with the deal.

Reference: https://docs.termina.ai/api-reference/data/product/get-concentration

## Authentication

- `Authorization` header (bearer token, required) — Bearer authentication of the form `Bearer <token>`, where token is your auth token.

## Servers

- `https://app.termina.ai` (Production server, default)
- `https://app.termina.dev` (Development server)
- `http://localhost:8000` (Local development server)

## Request

### Path parameters

- `group_id` (integer, required)
- `deal_id` (integer, required)

### Query parameters

- `user_type` (enum, required)
  - Allowed values: `business`, `consumer`, `supplier`, `asset`, `labor`, `business_user`
- `metric` (string, required)
- `freq` (enum, optional)
  - Allowed values: `M`, `Q`, `A`

## Response

### 200

Successful Response

- `time_series_metrics` (list of ConcentrationTimeseriesDetail, optional, nullable) — The time series metrics for the concentration of the amount. The top 5, 10, and 20 users are shown, as well as the top 10% and 20% of users, and some other supporting aggregate concentration metrics.
- `endpoint_top_users` (list of ConcentrationEndpointTopUsersDetail, optional) — Detail for the top users at the endpoint. Up to the top 100 users are show.
- `endpoint_cdf` (list of ConcentrationEndpointCDFDetail, optional) — The detailed cumulative distribution function (CDF). The CDF is presented at the top 100 users, and beyond that it is presented at approximately evenly spaced quantiles. This approach enables robustness to extremely large user bases. The CDF is presented for both users and amount.

## Errors

### 422 Unprocessable Entity Error

Validation Error

- `detail` (list of ValidationError, optional)

## Types

### ConcentrationTimeseriesDetail

- `date` (string, required) — The date of the entry.
- `top_5_count` (double, optional, nullable) — The share of amount in the top 5 users.
- `top_10_count` (double, optional, nullable) — The share of amount in the top 10 users.
- `top_20_count` (double, optional, nullable) — The share of amount in the top 20 users.
- `top_10_percent` (double, optional, nullable) — The share of amount in the top 10% of users.
- `top_20_percent` (double, optional, nullable) — The share of amount in the top 20% of users.
- `mean` (double, optional, nullable) — The mean amount in the period.
- `p25` (double, optional, nullable) — The 25th percentile of the amount in the period.
- `median` (double, optional, nullable) — The 50th percentile of the amount in the period.
- `p75` (double, optional, nullable) — The 75th percentile of the amount in the period.
- `p90` (double, optional, nullable) — The 90th percentile of the amount in the period.
- `average_to_median` (double, optional, nullable) — The ratio of the mean to the median amount in the period.
- `gini_coefficient` (double, optional, nullable) — The Gini coefficient of the amount in the period, ranging from 0 to 1.

### ConcentrationEndpointTopUsersDetail

- `user_id` (string, required) — The user identifier.
- `amount` (double, required) — The amount for the user.
- `amount_percent` (double, required) — The pdf of the total amount for the user.

### ConcentrationEndpointCDFDetail

- `method` (string, required) — The method used. When 'top_user', the value represents the CDF at the exact value of a top user. When 'distribution_quantile', the value represents the CDF at an approximately evenly spaced quantile.
- `amount` (double, required) — The amount for the CDF.
- `cdf_users` (double, optional) — The cumulative distribution function of the users, sorted smallest to largest. This evenly weights users by count, and represents (1 - top quantile) of the user
- `cdf_amount` (double, optional) — The cumulative distribution function of the amount, sorted smallest to largest. This tells us what percentage of all amount is held by the bottom x% of users.

### ValidationError

- `loc` (list of ValidationErrorLocItems, required)
- `msg` (string, required)
- `type` (string, required)
- `input` (any, optional)
- `ctx` (ValidationErrorCtx, optional)

### ValidationErrorLocItems

### ValidationErrorCtx

## Examples

**Response**

```json
{
  "time_series_metrics": [
    {
      "date": "2026-01",
      "top_5_count": 5,
      "top_10_count": 10,
      "top_20_count": 20,
      "top_10_percent": 0.1,
      "top_20_percent": 0.2,
      "mean": 100,
      "p25": 50,
      "median": 100,
      "p75": 150,
      "p90": 200,
      "average_to_median": 1.5,
      "gini_coefficient": 0.7
    }
  ],
  "endpoint_top_users": [
    {
      "user_id": "user_1",
      "amount": 100,
      "amount_percent": 0.1
    }
  ],
  "endpoint_cdf": [
    {
      "method": "top_user",
      "amount": 100,
      "cdf_users": 0.7,
      "cdf_amount": 0.88
    }
  ]
}
```

**SDK Code**

```python
import requests

url = "https://app.termina.ai/api/v1/group/1/deal/1/data/concentration"

querystring = {"user_type":"business","metric":"metric"}

headers = {"Authorization": "Bearer <token>"}

response = requests.get(url, headers=headers, params=querystring)

print(response.json())
```

```javascript
const url = 'https://app.termina.ai/api/v1/group/1/deal/1/data/concentration?user_type=business&metric=metric';
const options = {method: 'GET', headers: {Authorization: 'Bearer <token>'}};

try {
  const response = await fetch(url, options);
  const data = await response.json();
  console.log(data);
} catch (error) {
  console.error(error);
}
```

```go
package main

import (
	"fmt"
	"net/http"
	"io"
)

func main() {

	url := "https://app.termina.ai/api/v1/group/1/deal/1/data/concentration?user_type=business&metric=metric"

	req, _ := http.NewRequest("GET", url, nil)

	req.Header.Add("Authorization", "Bearer <token>")

	res, _ := http.DefaultClient.Do(req)

	defer res.Body.Close()
	body, _ := io.ReadAll(res.Body)

	fmt.Println(res)
	fmt.Println(string(body))

}
```

```ruby
require 'uri'
require 'net/http'

url = URI("https://app.termina.ai/api/v1/group/1/deal/1/data/concentration?user_type=business&metric=metric")

http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true

request = Net::HTTP::Get.new(url)
request["Authorization"] = 'Bearer <token>'

response = http.request(request)
puts response.read_body
```

```java
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.Unirest;

HttpResponse<String> response = Unirest.get("https://app.termina.ai/api/v1/group/1/deal/1/data/concentration?user_type=business&metric=metric")
  .header("Authorization", "Bearer <token>")
  .asString();
```

```php
<?php
require_once('vendor/autoload.php');

$client = new \GuzzleHttp\Client();

$response = $client->request('GET', 'https://app.termina.ai/api/v1/group/1/deal/1/data/concentration?user_type=business&metric=metric', [
  'headers' => [
    'Authorization' => 'Bearer <token>',
  ],
]);

echo $response->getBody();
```

```csharp
using RestSharp;

var client = new RestClient("https://app.termina.ai/api/v1/group/1/deal/1/data/concentration?user_type=business&metric=metric");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer <token>");
IRestResponse response = client.Execute(request);
```

```swift
import Foundation

let headers = ["Authorization": "Bearer <token>"]

let request = NSMutableURLRequest(url: NSURL(string: "https://app.termina.ai/api/v1/group/1/deal/1/data/concentration?user_type=business&metric=metric")! as URL,
                                        cachePolicy: .useProtocolCachePolicy,
                                    timeoutInterval: 10.0)
request.httpMethod = "GET"
request.allHTTPHeaderFields = headers

let session = URLSession.shared
let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { (data, response, error) -> Void in
  if (error != nil) {
    print(error as Any)
  } else {
    let httpResponse = response as? HTTPURLResponse
    print(httpResponse)
  }
})

dataTask.resume()
```