Read 13F cover pages and holdings together
Get a manager's Form 13F-HR cover page and its full information table from SecFeed, check the totals, and list the largest positions with portfolio weights.
A Form 13F-HR has two parts. The cover page (the primary XML document) names the manager, the report period, the report type and the summary totals: number of table entries and total value. The information table lists every position. Reading both lets you confirm that you have the whole portfolio before you analyze it.
SecFeed serves the two parts from two endpoints: /v1/form-13f for cover pages and /v1/form-13f/holdings for the information table rows.
Fetch the cover page and the holdings
This example uses Dodge & Cox (CIK 200217). fields=flat returns the curated cover fields without the full XML tree. The period parameter on the holdings endpoint uses the same MM-DD-YYYY format as the 13F cover page.
import os
from collections import defaultdict
import requests
BASE = "https://secfeedapi.com"
HEADERS = {"Authorization": f"Bearer {os.environ['SECFEED_KEY']}"}
CIK = 200217 # Dodge & Cox
r = requests.get(f"{BASE}/v1/form-13f", params={"cik": CIK, "fields": "flat"}, headers=HEADERS, timeout=120)
r.raise_for_status()
cover = r.json()["filings"][0]
flat = cover["flat"]
print(cover["formType"], "filed", cover["filedAt"], "|", flat["manager"])
print("Period:", flat["period"], "| report type:", flat["reportType"])
print(f"Entries: {flat['entries']:,.0f} | total value: ${flat['totalValue']:,.0f}")
r = requests.get(f"{BASE}/v1/form-13f/holdings", params={"cik": CIK, "period": flat["period"], "size": 1000},
headers=HEADERS, timeout=120)
r.raise_for_status()
rows = r.json()
total = sum(h["value"] for h in rows)
print(f"\nHoldings rows: {len(rows)} | sum of values: ${total:,.0f}")
positions = defaultdict(float)
for h in rows:
positions[(h["issuer"], h["cusip"], h["put_call"] or "")] += h["value"]
print(f"\n{'Issuer':<32}{'CUSIP':<11}{'Value':>18}{'Weight':>8}")
for (issuer, cusip, pc), v in sorted(positions.items(), key=lambda x: -x[1])[:10]:
print(f"{(issuer + (' ' + pc if pc else ''))[:31]:<32}{cusip:<11}{v:>18,.0f}{v / total:>8.1%}")
Output:
13F-HR filed 2026-08-13 | Dodge & Cox
Period: 06-30-2026 | report type: 13F HOLDINGS REPORT
Entries: 222 | total value: $191,008,088,994
Holdings rows: 222 | sum of values: $191,008,088,994
Issuer CUSIP Value Weight
Johnson Controls International G51502105 8,149,432,237 4.3%
The Charles Schwab Corp. 808513105 7,101,867,203 3.7%
RTX Corp. 75513E101 6,662,036,733 3.5%
CVS Health Corp. 126650100 5,173,820,539 2.7%
Microsoft Corp. 594918104 4,788,170,142 2.5%
Booking Holdings, Inc. 09857L108 4,551,705,968 2.4%
Humana, Inc. 444859102 4,345,737,744 2.3%
Alphabet, Inc. 02079K107 4,226,214,403 2.2%
MetLife, Inc. 59156R108 4,097,759,602 2.1%
Sunbelt Rentals Holdings, Inc. 866966104 4,096,716,044 2.1%
Check the totals
The cover page reports 222 entries and a total of $191,008,088,994. The information table returned 222 rows that sum to exactly the same figure, so the holdings are complete. Run this check whenever you load a 13F: if a manager files a 13F-HR/A amendment that restates the table, or reports some positions confidentially, the counts will not match and you will know to look further.
Since January 2023 13F values are reported in whole dollars; earlier reports used thousands of dollars. Keep that in mind before comparing values across years.
Report types
The reportType field tells you what the filing contains:
- 13F HOLDINGS REPORT: the manager reports all of its positions in this filing
- 13F NOTICE: another manager reports the positions (the filer has an information table of zero rows)
- 13F COMBINATION REPORT: some positions here, some reported by other managers
When you see a notice, the positions live in another manager's filing. The otherManagers count on the cover page tells you how many are involved.
Positions with puts and calls
The holdings rows include put_call. The example groups by issuer, CUSIP and put or call so that an option position never adds to a common stock position. For voting analysis, use vote_sole, vote_shared and vote_none on each row.