/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 AS-FILED (not split-adjusted) so split events show as instantaneous N× jumps on the timeline — this is the correct as-filed semantic for a single-fund-single-position view. For split-adjusted aggregations across funds use GET /api/v1/tickers/{ticker}/fund-trends.
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. |
| 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). AS-FILED, NOT split-adjusted — a 4:1 split between two consecutive quarters appears as a 4× jump. For split-adjusted aggregation use [GET /api/v1/tickers/{ticker}/fund-trends](/docs/ticker-research/get-tickers-ticker-fund-trends). |
| 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` for this entry (`prev_shares=0` on the first entry). Positive = bought; negative = trimmed; zero = held flat. Use to spot major buying/trimming episodes — Berkshire's 2017-03-31 AAPL row shows `shares_delta = +71,997,454` (a continuation of the late-2016 ramp). |
| 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
- "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/{cik}/cusip/{cusip}/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).