/api/v1/form-13f/fund/{cik}/cusip/{cusip}/historyPer-quarter share + value history for a single (fund, CUSIP) position — the chronological trail of one security held by one filer across every 13F-HR quarter we have on file.
Per-quarter share + value history for a single (fund, CUSIP) position — the chronological trail of one security held by one filer across every 13F-HR quarter we have on file.
Why use this
Common use case
Returns the full chronological trail of ONE position held by ONE filer — every quarter we have a 13F filing where the (CIK, CUSIP) appeared, the shares held, the reported value, the QoQ share delta, and a transaction-type classification. Used by the FinRadar.ai filer-page transaction-timeline chart on the chevron-expanded position row (replaces the placeholder that used to read 'Transaction-timeline chart coming next — needs per-ticker quarterly history endpoint').
Why CUSIP-keyed (not ticker): tickers change. Mergers (SHEN → CALX 2024), spinoffs (GOOG/GOOGL 2014), ticker reuse, and corporate-action chains (SIRI's 2024 reverse split flipped CUSIP 82968B103 → 829933100 mid-quarter) all break ticker-keyed timelines. CUSIPs are the canonical 13F security identifier — frontend rows from GET /api/v1/form-13f/fund/{cik} already carry both cusip and canonicalCusip, pass either back here.
Filing selection per quarter matches GET /api/v1/form-13f/fund/{cik} and CostBasisService exactly — for each period_of_report we pick the filing with the MOST non-option holdings (#264 amendment-handling). So a fund that filed a 36-holding 13F-HR and then a 4-holding 13F-HR/A 'correction' amendment shows the 36-holding original on this endpoint, NOT the 4-holding amendment.
Closed positions appear in the history up through their last reported quarter — once the fund has zero shares of the security, there is no row for subsequent quarters (no synthetic 0-share emit). Frontends rendering the chart should interpret 'no entry for quarter X' as 'position closed before X'; the chart axis can drop to 0 by interpolating. Share counts are SPLIT-ADJUSTED — forward-adjusted to the latest split basis via the split feed (ticker-keyed) so a stock split is NOT mislabelled as a phantom buy/sell; the timeline is continuous and only real trading moves the line. Each row also carries shares_raw (the literal as-filed count), and the response carries top-level split_adjusted + splits[] for reconciliation. value is left raw (13F value = shares × quarter-end price, already split-invariant). If the ticker can't be resolved or the split-feed read fails, the endpoint degrades to raw (unadjusted) shares rather than erroring.
Parameters
| Name | In | Required | Default | Allowed | Description | Example |
|---|---|---|---|---|---|---|
| cik | path | required | — | — | Fund CIK in 10-char zero-padded form (e.g. `0001067983` for Berkshire Hathaway, `0001536411` for Duquesne Family Office). Server-side normalization handles 6/7/10-char input forms (the endpoint accepts `1067983` and pads it for you). | 0001067983 |
| cusip | path | required | — | — | Canonical 9-character CUSIP for the security (`current_cusip` column in `normalized_holdings_deduped`). Pass the `cusip` (or `canonicalCusip` for chained-CUSIP fallback) from any holdings row on [GET /api/v1/form-13f/fund/{cik}](/docs/institutional-holdings/form-13f-api/get-form-13f-fund-cik). Validated server-side: alphanumeric only, ≤ 12 chars — anything else returns 400 BAD_REQUEST. | 037833100 |
Response schema
| Field | Type | Nullable | Description |
|---|---|---|---|
| cik | string | no | 10-char zero-padded fund CIK echoed from the request — useful for asserting your client passed the CIK you intended after CIK-padding normalization. |
| cusip | string | no | Canonical CUSIP echoed from the request (uppercase-normalized server-side). |
| ticker | string | yes | Resolved ticker via `cusip_mappings` (best-effort LEFT JOIN). Null when the CUSIP is unmapped (~3% in steady state) or for delisted issuers without a current ticker. |
| name | string | yes | Issuer name (`cusip_mappings.security_name`, typically all-caps EDGAR convention — e.g. `APPLE INC`). Null when no mapping row exists. |
| quarters | integer | no | Convenience pointer to `history.length` — number of distinct quarter-end dates in the response. Active long-term holdings show 30+ quarters (Berkshire AAPL = ~40 quarters since 2016-Q1); new positions show 1-2 quarters. |
| split_adjusted | boolean | no | True when at least one stock-split factor was applied to `history[].shares` (i.e. the security split at some point after one of the reported quarters). False when no splits were found for the ticker or the ticker could not be resolved (in which case `shares` == `shares_raw` for every row). |
| splits | array | no | The split events (from the corporate-actions/split feed, ticker-keyed) used to forward-adjust shares — `[{ date: 'YYYY-MM-DD', ratio: number }]`, e.g. AAPL = `[{date:'2014-06-09',ratio:7},{date:'2020-08-31',ratio:4}]`. Empty `[]` when none apply. Provided for transparency/reconciliation. |
| history | array | no | Per-quarter rows sorted by `quarter_date` ASC (oldest first). One entry per `period_of_report` where this CUSIP appears in the fund's chosen 13F filing for that quarter. Positions that were fully sold (closed) simply stop appearing — there is no synthetic 0-share row. |
| history[].quarter_date | string | no | ISO `YYYY-MM-DD` of the filing's `period_of_report` (always a calendar quarter end: 03-31, 06-30, 09-30, 12-31). |
| history[].shares | integer | no | Sum of `number_of_shares` across all sub-advisor partitions for this (filing, CUSIP), FORWARD-ADJUSTED to the latest split basis using the split feed — so a stock split is NOT mislabelled as a giant phantom buy/sell. Continuous across splits: a 4:1 split nets to ~0, and only real trading moves the count. Use `shares_raw` for the literal as-filed value. (Same split-adjustment methodology as [GET /api/v1/tickers/{ticker}/fund-trends](/docs/ticker-research/get-tickers-ticker-fund-trends).) |
| history[].shares_raw | integer | no | The literal as-filed `number_of_shares` sum for this quarter, BEFORE split adjustment — kept for reconciliation against the raw 13F filing. Equals `shares` when no split applies to this quarter. |
| history[].value | integer | no | Sum of `value_of_shares` across all sub-advisor partitions for this (filing, CUSIP). USD, post-Plan-51 thousands-vs-actual normalization. For BlackRock/Vanguard-class index books a single position can be $200B+; mid-tier hedge fund positions are typically $10M-$1B. |
| history[].shares_delta | integer | no | `shares - prev_shares` computed on the SPLIT-ADJUSTED counts (`prev_shares=0` on the first entry). Positive = bought; negative = trimmed; zero = held flat. Because shares are split-adjusted, a split no longer shows as a phantom delta — e.g. Berkshire's 2020-09-30 AAPL row (the quarter of the 4:1 split) is now `shares_delta = -36,326,710` (the real trim), not the raw `+699,139,988` jump a naive as-filed delta would report. |
| history[].transaction_type | string | no | Classification of this quarter's transition: `new` (first entry, or re-entry after a temporary sell-out reflected as a zero row — note that the SQL today only returns quarters where the position exists with non-zero shares, so re-entries appear as fresh `new` rather than `re-opened`), `increased` (delta > 0), `decreased` (delta < 0), `unchanged` (delta == 0). |
Sample response
- "cik": "0001067983"
- "cusip": "037833100"
- "ticker": "AAPL"
- "name": "APPLE INC"
- "quarters": 4
- "split_adjusted": true
- "splits":
- "history":
Errors
| Status | Label | Description |
|---|---|---|
| 200 | OK | Request succeeded. |
| 400 | Bad Request | Invalid query, body, or path parameter. |
| 401 | Unauthorized | Missing or invalid Authorization header / api_Token. |
| 402 | Payment Required | Insufficient token balance for this call. Top up |
| 429 | Too Many Requests | Rate limit exceeded for your tier (see /pricing for tier limits). Tier limits |
| 500 | Server Error | Unexpected server-side failure. Retry with backoff; report if persistent. |
Code samples
curl "https://api.finradar.ai/api/v1/form-13f/fund/0001067983/cusip/037833100/history" \
-H "Authorization: Bearer YOUR_JWT_TOKEN"Generate an API key in /account/credentials to run live queries (literal YOUR_API_KEY placeholder shown until then).