13F Filings API: Pull Holdings, Managers and Filing Dates
How to pull 13F cover pages and holdings with an API, filter by filing date instead of quarter, and what an industry breakdown or performance figure actually needs.
- A 13F filings API is really two endpoints, one for the cover page a manager files and one for the position rows inside it.
- Filter by filedAt with startDate and endDate when you want filing date, since filing date and reporting period are not the same thing.
- An industry breakdown is not a field the SEC publishes; build it by mapping each CUSIP to a ticker and then to its SIC code.
- The data can show how a position's size changed between quarters, but it cannot compute a dollar return without a separate price source.
A 13F filings API needs to give you two different things: the cover page a manager files each quarter, and the individual position rows underneath it. SecFeed splits these into two endpoints with filters for CUSIP, CIK and filing date, and leaves out numbers the SEC itself does not publish, like an industry split or a return. This guide covers both endpoints, how to filter by filing date instead of quarter, and what it actually takes to build the industry and performance views people search for next.
Two endpoints, one filing
Form 13F has a cover page (who is filing, for which quarter, how many positions, what they add up to) and an information table (the positions themselves). SecFeed keeps them as two endpoints so you are not pulling the whole XML document just to read the manager's name.
| Endpoint | Returns | Typical filter |
|---|---|---|
GET /v1/form-13f | Cover pages: manager, period, report type, entry count, total value | cik, startDate, endDate |
GET /v1/form-13f/holdings | Position rows: issuer, CUSIP, value, shares, voting authority, put or call | cusip, cik, period |
Both endpoints read the same underlying filings, so a manager's CIK and a filing's period field (in MM-DD-YYYY, the format the form itself uses) line up across the two calls.
Every holder of one security, by CUSIP
To answer "who holds this stock," query holdings by CUSIP and quarter. Rows come back sorted by value, so the largest positions are first:
curl "https://secfeedapi.com/v1/form-13f/holdings?cusip=037833100&period=06-30-2026&size=5" \
-H "Authorization: Bearer YOUR_API_KEY"
[
{
"accession": "0001234567-26-012345",
"filer_cik": 1067983,
"filer": "EXAMPLE CAPITAL MANAGEMENT LLC",
"period": "06-30-2026",
"filed": "2026-08-13",
"issuer": "APPLE INC",
"title": "COM",
"cusip": "037833100",
"value": 182400000,
"value_unit": "dollars",
"shares": 915000,
"sh_prn": "SH",
"put_call": null,
"discretion": "SOLE",
"vote_sole": 915000,
"vote_shared": 0,
"vote_none": 0
}
]
value_unit matters more than it looks. Filings made before January 3, 2023 report value in thousands of dollars; filings after that date report dollars, following an SEC rule change. Some managers kept reporting in thousands anyway, so check value_unit on the row rather than assuming it from the filing date, and if a value divided by shares looks absurdly cheap or expensive for the security, that is the usual sign of a unit mismatch. See our guide to what a 13F filing covers for the rest of the cover page fields.
Get this data as clean JSON
SecFeed turns SEC filings into structured data with one API call: GET /v1/form-13f/holdings?cusip=037833100&period=06-30-2026. Free key, no card needed.
One manager's full portfolio, by CIK
To answer "what does this manager hold," query by CIK and period instead of CUSIP:
from secfeed import Client
sf = Client("YOUR_API_KEY")
rows = sf.holdings_13f(cik=1067983, period="06-30-2026")
for r in rows:
print(r["issuer"], r["cusip"], r["value"], r["value_unit"])
The REST endpoint itself also takes from and size for paging past the default page size, which is useful when calling it directly with curl instead of the SDK.
Run the same loop for a second period and diff the two sets of CUSIPs and share counts to see what the manager added, trimmed or closed between quarters. We cover this pattern with real manager CIKs in 13F filings of top investors.
Filtering by filing date instead of quarter
"13F filing dates" and "reporting period" look interchangeable and are not. period is the quarter the holdings describe; filedAt (on cover pages) is the day the manager actually submitted the report, which Rule 13f-1 allows up to 45 days after the quarter ends. Two managers with the same period can have filedAt values weeks apart, and amendments add a third date entirely. Our 13F filing deadlines guide walks through the 45-day rule and why most filings cluster near it.
To pull everything filed in a date window, regardless of which quarter it reports on, filter the cover page endpoint:
curl "https://secfeedapi.com/v1/form-13f?startDate=2026-10-01&endDate=2026-10-31&fields=flat&size=50" \
-H "Authorization: Bearer YOUR_API_KEY"
fields=flat drops the raw XML and returns just the manager, period, report type and totals, which is enough for most date-range scans. Add formType=13F-HR/A to isolate amendments, which is the only reliable way to separate late corrections from original reports in a date window.
Building a 13F industry breakdown yourself
No part of Form 13F states an industry. The information table only has an issuer name, a CUSIP and a security title, so "13F industry breakdown" has to be built by joining three things a manager's holdings do not carry on their own:
- Holdings by CUSIP, from
/v1/form-13f/holdings. - CUSIP to ticker and CIK, from
/v1/mapping/cusip, which returns the issuer name used in 13F filings and the listed companies that match it. - CIK to SIC code, from
/v1/entities, whosesicandsicDescriptionfields give the four-digit Standard Industrial Classification code and its name.
from secfeed import Client
sf = Client("YOUR_API_KEY")
holdings = sf.holdings_13f(cik=1067983, period="06-30-2026")
totals = {}
for row in holdings:
match = sf.map_cusip(row["cusip"])
if not match or not match[0].get("matches"):
continue
cik = match[0]["matches"][0]["cik"]
entity = sf.entity(cik)
sic = entity.get("sicDescription", "Unclassified")
totals[sic] = totals.get(sic, 0) + row["value"]
This is a lookup per holding, so it works well for one manager's portfolio but is not something to run across every 13F filer at once without caching the CUSIP to SIC mapping locally. See the EDGAR Company Profiles API docs for the rest of the entity profile fields.
What a 13F holder performance number actually needs
"13F holder performance" implies a return, and a return needs a price at the start and end of the period, which is not in a 13F filing at all. The information table gives you shares and a reported value, both snapshots at one point in time, with no cost basis and no price history attached.
What you can build from 13F data alone is a change in position size: pull the same cik and cusip for two consecutive period values and compare shares. That tells you whether a manager added to, trimmed, or closed a position, without implying a return.
Coverage and limits
| Item | Detail |
|---|---|
| Date range | 1999 onward. Rows from 1999 through the first quarter of 2013 are parsed from the plain text and HTML tables managers filed before the SEC required XML; rows from the second quarter of 2013 on come from the SEC's structured 13F data sets. |
| Pre-2013 rows | cusip_source on each row says text or xml. Some 1999 to 2013 filers identified a holding by something other than a CUSIP (a SEDOL, an exchange ticker); identifier_type flags those, and cusip is null rather than guessed. |
| Value units | Thousands of dollars before January 3, 2023, dollars after. Check value_unit on each row. |
| CUSIP mapping rate limit | /v1/mapping/cusip is capped at 50 lookups a day per key, so cache the CUSIP to ticker mapping rather than re-resolving the same securities on every run. |
Frequently asked questions
What is the difference between a 13F cover page and 13F holdings data?
The cover page, from /v1/form-13f, is one record per filing: the manager, the quarter, the report type and the totals it claims. Holdings, from /v1/form-13f/holdings, is one record per position inside that filing: the issuer, CUSIP, value and share count.
How do I filter 13F filings by filing date instead of quarter?
Use startDate and endDate on /v1/form-13f, which filter by the date the manager filed. Use period on either endpoint when you want a specific reporting quarter, since filing date and reporting quarter are tracked separately and can be weeks apart under the 45-day deadline.
Does a 13F filings API return an industry breakdown directly?
No. Form 13F does not state an industry. Build one by resolving each holding's CUSIP to a company with /v1/mapping/cusip, then looking up that company's SIC code with /v1/entities.
Can I calculate a fund's performance from 13F data?
Not a dollar return. 13F filings report share counts and a reported value at one point in time, with no price history or cost basis. You can track how a position's share count changed between quarters, which shows activity without implying a return.
How far back does 13F holdings data go?
To 1999. Filings before the second quarter of 2013 are parsed from plain text and HTML information tables rather than the SEC's structured XML, so some fields such as voting authority can be missing on older rows even when the position itself parsed correctly.
Get this data as clean JSON
SecFeed turns SEC filings into structured data with one API call: GET /v1/form-13f/holdings?cusip=037833100&period=06-30-2026. Free key, no card needed.
For information only, not investment advice. Data from public SEC filings; verify important figures on SEC.gov. See our AI Disclosure.