Every US public company files its financials with the SEC, and the SEC makes all of it available for free through public endpoints on data.sec.gov — submissions (filing metadata) and companyfacts (XBRL financial data). No login, no API key, no paywall, and the SEC explicitly permits programmatic access.
The catch: companyfacts files are large nested JSON, the SEC caps you at 10 requests/second, and tickers don't map directly to company identifiers (the SEC keys everything by CIK number).
This tutorial shows how to get the same data as structured JSON with a single API call — using a pay-per-event actor that handles CIK resolution, rate limiting, and XBRL normalization for you.
What we're building
A pipeline that, for any ticker or CIK:
- Resolves the ticker to a CIK via the SEC's company list
- Pulls recent filings (
10-K,10-Q,8-K,4for Form 4,13F-HR,S-1,DEF 14A…) with full metadata - Fetches XBRL concept time-series (Revenue, Net Income, EPS, Assets, …) with up to the 20 most recent values each
- Returns everything as JSON records
Prerequisites
- An Apify account (the free tier is enough — a few test runs cost cents)
-
curlor any HTTP client - A ticker or CIK you care about — let's use
AAPL
Step 1: The API call
curl -X POST "https://api.apify.com/v2/acts/gp005~edgar-xbrl-fundamentals/runs" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ***" \
-d '{
"tickers": ["AAPL"],
"mode": "both",
"formTypes": ["10-K"],
"maxFilings": 2
}'
mode: "both" returns filings and financial data in one run. You can also use "filings" or "financials" alone. formTypes filters the filing list, and maxFilings caps it (up to 500 per company).
formTypes matches EDGAR's own form codes exactly — copy the code from the filing you're targeting. Form 4 insider transactions are 4 (not "Form 4"), and a 13F holdings report is 13F-HR (there is no 13-F code).
Step 2: Reading the output
Two kinds of records come back.
Filing records — metadata about each filing:
{
"cik": "0000320193",
"ticker": "AAPL",
"companyName": "Apple Inc.",
"form": "10-K",
"filedDate": "2025-10-31",
"reportDate": "2025-09-27",
"accessionNumber": "0000320193-25-000079",
"primaryDocument": "aapl-20250927.htm",
"fileUrl": "https://www.sec.gov/Archives/edgar/data/320193/000032019325000079/aapl-20250927.htm"
}
Concept records — normalized financial time-series:
{
"cik": "0000320193",
"ticker": "AAPL",
"companyName": "Apple Inc.",
"concept": "us-gaap/NetIncomeLoss",
"unit": "USD",
"label": "Net Income (Loss) Attributable to Parent",
"values": [
{
"start": "2026-03-29",
"end": "2026-06-27",
"val": 29789000000,
"accn": "0000320193-26-000020",
"fy": 2026,
"fp": "Q3",
"form": "10-Q",
"filed": "2026-07-31",
"frame": "CY2026Q2"
}
]
}
Every value keeps its period start/end, fiscal year and period, the accession number and form it came from, and the filing date — which makes charting or screening logic straightforward. Balance-sheet concepts (Assets, StockholdersEquity) carry only an end, since they are point-in-time.
Step 3: Financial concepts
The actor reads the SEC's companyfacts API, which covers thousands of US-GAAP and DEI XBRL concepts. Common ones:
| Concept | What it is |
|---|---|
Revenues |
Total revenue |
RevenueFromContractWithCustomerExcludingAssessedTax |
Revenue, for filers that switched off the Revenues tag |
NetIncomeLoss |
Net income |
EarningsPerShareBasic |
Basic EPS |
Assets |
Total assets |
StockholdersEquity |
Shareholders' equity |
Pass them explicitly with xbrlConcepts (defaults apply if omitted). Each concept returns up to the 20 most recent values.
One gotcha worth knowing: companies retire XBRL tags. Apple's us-gaap/Revenues series stops in 2018; current Apple filings report revenue under us-gaap/RevenueFromContractWithCustomerExcludingAssessedTax. If a concept comes back with no recent values, that's usually why — name the tag the filer actually uses.
Step 4: Batch and automate
Pass multiple tickers or CIKs in one run:
{
"tickers": ["AAPL", "MSFT", "NVDA"],
"mode": "financials",
"xbrlConcepts": ["Revenues", "NetIncomeLoss", "EarningsPerShareBasic"]
}
Then schedule it — daily or weekly — via Apify Console, or trigger it with a webhook whenever you need fresh numbers. Common patterns:
-
Earnings alerts: schedule a daily filings run, filter
8-Ks, and webhook the results into Slack - Fundamentals feed: nightly financials run for your watchlist → CSV/JSON into your datastore
- Screening: pull Assets/Equity across an index and compute metrics (ROE, margins) server-side
Step 5: What it costs
Pay-per-event — you only pay for what a run actually fetches:
-
actor-start: $0.01 per run -
filing-fetched: $0.003 per filing record -
financial-concept-fetched: $0.005 per concept per company
A measured smoke run (AAPL, 10-K, 2 filings + 10 concepts) returned 12 records in ~4 seconds for $0.066 in event charges — 0.00466 compute units, $0.00105 of platform usage. To hard-cap spend, pass the maxTotalChargeUsd run option; the actor checks the charge limit after every event and exits gracefully instead of running up the bill.
Rate limits and compliance
The SEC allows up to 10 requests/second on data.sec.gov. The actor issues its requests one at a time with a 120 ms minimum gap between them (~8 req/s), so normal workloads never hit the cap — no proxy needed. Data comes exclusively from the SEC's official public APIs, which the SEC permits for programmatic access. The actor is not affiliated with or endorsed by the SEC.
FAQ
Is the SEC EDGAR API free?
The SEC's EDGAR endpoints are free and public. You only pay for this actor's per-event usage when a run actually fetches data.
Do I need a SEC EDGAR API key?
No. The SEC doesn't issue keys for data.sec.gov — it asks for a descriptive User-Agent, which the actor sends for you. No signup, no token, no OAuth.
What is a CIK and how do I find it?
CIK (Central Index Key) is the SEC's unique numeric company identifier — Apple is 0000320193. The actor resolves tickers to CIKs automatically; you can also pass CIKs directly.
Which SEC filing types are supported?
All of them — 10-K, 10-Q, 8-K, 4, 13F-HR, S-1, DEF 14A and thousands more. Use formTypes to filter, with EDGAR's own form codes.
Does this work from Python?
Yes — run it through the Apify API with apify-client, and the dataset comes back as a list of dicts. You skip the usual chores: fetching company_tickers.json to map tickers to CIKs, back-off around the 10 req/s budget, and walking the nested companyfacts structure.
What is XBRL financial data?
The machine-readable format US companies use to tag their financial statements; the SEC publishes it via its companyfacts API, which this actor normalizes into JSON time-series.
Related
If you also need change detection on SEC documents, check out the SEC EDGAR Filing Diff & Section-Level Redline Monitor — it monitors SEC filings and returns section-level redline diffs when a document changes.
API docs: https://apify.com/gp005/edgar-xbrl-fundamentals/input
Top comments (0)