---
title: "Concentration Risk"
method: GET
path: "/api/footnotes/concentration"
tags: ["Footnotes"]
---

# Concentration Risk

`GET /api/footnotes/concentration`

![Pro](https://img.shields.io/badge/Pro-8b5cf6)

Returns concentration-risk disclosures as time series: named-counterparty dependence (e.g. "Apple is 50% of revenue, up from 37% three years ago"), unnamed aggregates ("top ten customers"), and the same machinery for supplier, geographic, product, and credit concentration.

Unlike the other financials endpoints this response is **series-major**, not period-major: disclosures are grouped by `(riskType, benchmark)` category, e.g. customer × revenue vs customer × receivables, and each counterparty carries its own `history`. Grouping is by stable **category**, not raw XBRL member, so a filer switching benchmark members across years keeps one continuous series; the raw rider members are listed in `riskTypeMembers` / `benchmarkMembers` for auditability.

Counterparty names are the **filer's own extension members** (`rfmd:AppleMember` → "Apple"); no entity resolution is attempted, the label is the filer's own word. When the filer also tagged the dollar amount for the same counterparty and period (a minority of filers do), it attaches to the share point as `revenue`, converted per the `currency` parameter (spot for balance-date shares' amounts, period-average for flows) with the response-level `fx` audit block. Shares themselves are pure fractions and never converted.

**What this data can tell you:**
- Largest-customer share of revenue and its trend.
- Revenue vs receivables concentration on the same counterparty.
- Supplier dependence where disclosed.
- Whether diversification away from a key customer is actually happening.

**Data honesty notes:**
- `share` is a fraction of 1 (`0.50` = 50%). Mis-tagged whole percents are re-scaled and the point flagged `normalized: true`.
- In the quarterly view, full-year duration shares are not served as Q4 (a full-year share is not a fourth-quarter share); balance-date shares (e.g. receivables mix) do appear as Q4.
- Coverage is US-GAAP filers tagging the concentration axes; a filer that only discusses concentration in prose is not covered.

## Query parameters

- `symbol` string
- `cik` integer
- `cusip` string
- `composite_figi` string
- `share_class_figi` string
- `currency` string
- `period` 'annual' | 'quarter' — Base reporting period: `annual` or `quarter` (the periods companies actually report, without the derived `ttm` rollup).
- `limit` integer

## Response `200`

Concentration-risk series grouped by risk type and benchmark

- object
  - `groups` object[] — One group per (riskType, benchmark) category combination, groups with named counterparties first.
    - `riskType` 'customer' | 'supplier' | 'geographic' | 'product' | 'credit' | 'reinsurer' | 'governmentContracts' | 'labor' | 'lender' | 'other' | 'null', nullable — Stable category of the ConcentrationRiskByTypeAxis rider; `other` for unmapped members, null when the filer tagged no type.
    - `benchmark` 'revenue' | 'receivables' | 'payables' | 'costOfRevenue' | 'assets' | 'other' | 'null', nullable — Stable category of the ConcentrationRiskByBenchmarkAxis rider, what the share is a percentage OF.
    - `riskTypeMembers` string[] — Raw rider member QNames observed in this group.
    - `benchmarkMembers` string[]
    - `counterparties` object[] — One series per named counterparty, sorted by latest share descending.
      - `member` string — Raw XBRL member QName, a filer extension naming the counterparty
      - `name` string — Derived display label, the filer's own word, no entity resolution
      - `history` object[] — Newest first, up to `limit` points.
        - `period` string, date
        - `fiscalYear` integer
        - `fiscalPeriod` 'FY' | 'Q1' | 'Q2' | 'Q3' | 'Q4' — Fiscal period of a reported value: `FY` (annual) or `Q1`-`Q4` (quarterly).
        - `share` number — Concentration share as a fraction of 1
        - `normalized` boolean — Only present (as `true`) when the share was re-scaled from a mis-tagged whole percent.
        - `revenue` number — Disclosed dollar amount for this counterparty and period, when the filer tagged it
        - `currency` string, nullable — Currency of `revenue` after conversion; only present beside `revenue`
        - `dateFiled` string, date, nullable — SEC filing acceptance date of the share's source filing, use to gate point-in-time access
    - `aggregate` object, nullable — Share series tagged WITHOUT a named counterparty (e.g. "top ten customers combined"). Null when absent.
      - `history` object[]
        - `period` string, date
        - `fiscalYear` integer
        - `fiscalPeriod` 'FY' | 'Q1' | 'Q2' | 'Q3' | 'Q4' — Fiscal period of a reported value: `FY` (annual) or `Q1`-`Q4` (quarterly).
        - `share` number
        - `normalized` boolean
        - `dateFiled` string, date, nullable
  - `fx` FxConversion — Foreign-currency conversion audit for this period. Every monetary value in `facts` is in the requested `currency` (default **US dollars**). This block is absent when the period was already wholly in the target currency (e.g. a US filer with the default USD, nothing to convert). It is present when one or more line items were originally filed in a different currency and converted on the fly, and it records the exact rate(s) applied so the conversion can be reproduced. Rates come from the Frankfurter API (api.frankfurter.dev). Instant balance-sheet items use the spot rate at period end; flow income/cash-flow items use the day-weighted average rate over the period.
    - `targetCurrency` string, required — The currency (ISO 4217) every `facts` value was converted INTO, the value of the request `currency` parameter (default USD). The literal `original` here means no conversion was requested: each fact stays in its as-reported currency (see `unconverted` for the per-fact mapping).
    - `originalCurrencies` string[], required — Every source currency (ISO 4217) that appeared in this period, the union of converted, unconverted, and already-in-target. The target currency itself is listed when some facts were natively in it (e.g. a foreign filer reporting some lines in USD alongside its converted local currency), so a mixed period reflects its true composition rather than appearing wholly converted.
    - `rates` object[], required — One entry per (source currency, method) actually applied. `rate` is the multiplier: `target = original * rate`.
      - `from` string, required — ISO 4217 source currency that was converted.
      - `method` 'spot' | 'average', required — `spot` for instant balance-sheet items (rate at period end); `average` for flow income/cash-flow items (day-weighted mean over the period).
      - `rate` number, required — Multiply the original-currency amount by this to get the `targetCurrency` amount.
      - `effectiveDate` string, date — Spot only: the date (YYYY-MM-DD) the applied rate was published (≤ period end).
      - `start` string, date — Average only: period start (YYYY-MM-DD).
      - `end` string, date — Average only: period end (YYYY-MM-DD).
    - `unconverted` object — Facts that could NOT be converted (no published rate within tolerance, or an unsupported code/date), grouped by the currency they remain in: each key is a source ISO 4217 code, each value lists the curated fact names in `facts` still in that currency (NOT `targetCurrency`). Absent when everything converted. Use it to know exactly which figures to treat as native currency.

## Other responses

- `400` — Invalid parameters or symbol not found
- `403` — Feature not available on current plan

---

[API](https://skmtc.dev/stockfit/apis/stockfit-api.md) · [All operations](https://skmtc.dev/stockfit/apis/stockfit-api/llms.txt) · [OpenAPI document](https://skmtc-service-production.skmtc.workers.dev/v1/apis/stockfit/stockfit-api/revisions/de5578af3c78/schema)
