How do you get a company's SEC filings by CIK? Every US public company files with the SEC under a Central Index Key (CIK), and once you have that key the next problem is concrete: list every 10-K, 10-Q, and 8-K the company has submitted, with enough provenance on each row that any number you derive later can be traced back to its source document. That means three fields per filing: the accession number, the filing date, and the form type.
This post covers the second half of the identifier path. If you're still on the first half, turning a ticker into a CIK, read the ticker-to-identifier mapping guide first. The payoff here is the rest: the mental model for listing filings by company, the endpoint shape that returns the provenance fields, and the gotchas that surface once the data starts flowing.
From ticker to CIK to filings: the mental model#
Three identifiers do three different jobs.
The ticker is the human handle. It's what your users type and what your watchlists store, but it isn't durable: tickers change in renames and get recycled after delistings.
The CIK is the SEC's permanent key for a registrant. It's a zero-padded ten digit string (Apple Inc. is 0000320193), assigned once and never reused, and it survives ticker and name changes. It's also free: unlike CUSIP, ISIN, or SEDOL, which are licensed identifiers you can't reprint without an agreement, the CIK comes straight from the SEC's public data.
The accession number identifies one submission. Every document a registrant files, from a 10-K down to a single Form 4, gets exactly one, in a shape like 0000320193-25-000073. Treat it as an opaque unique string rather than parsing meaning out of it.
Those three identifiers chain into a provenance model: company (CIK) to submission (accession number) to data point. A revenue figure in a fundamentals table is an extract from a specific filing; the accession number and filing date tell you which one. That traceability is what makes filing-derived data usable for compliance and research work. When an auditor, a reviewer, or your own backtest asks where a number came from, the answer is a filing you can pull up, not a vendor's word.
Calling the SEC filings API#
SiftingIO keys its filing endpoints by ticker (tickers are case-insensitive), and the company profile carries the SEC identifiers, so resolving and listing takes two calls. First the profile:
curl -H "X-API-Key: $SIFTING_KEY" \
"https://api.sifting.io/v1/fnd/stocks/AAPL/profile"
The profile returns company metadata including the zero-padded CIK, the SIC classification, and the fiscal year end. Then the filings list:
curl -H "X-API-Key: $SIFTING_KEY" \
"https://api.sifting.io/v1/fnd/stocks/AAPL/filings?limit=50"
Every row carries the three provenance fields: accession number, filing date, and form type. You can filter by form type and date range to narrow the list to, say, annual reports since 2020; the exact query parameters and field names are documented at /docs/filings, along with sibling endpoints that pre-filter common cases (8-K material events by item code, earnings releases, Schedule 13D/13G ownership, DEF 14A proxy statements).
Pagination is cursor-based. The response's meta object carries next_cursor, which is null on the last page. A complete pull in Python:
import os
import requests
import pandas as pd
BASE = "https://api.sifting.io/v1"
HEADERS = {"X-API-Key": os.environ["SIFTING_KEY"]}
rows, cursor = [], None
while True:
params = {"limit": 100}
if cursor:
params["cursor"] = cursor
resp = requests.get(f"{BASE}/fnd/stocks/AAPL/filings",
headers=HEADERS, params=params)
resp.raise_for_status()
payload = resp.json()
rows.extend(payload["data"]) # each row: accession number, form type, filing date
cursor = payload["meta"]["next_cursor"]
if cursor is None:
break
df = pd.DataFrame(rows)
print(df.head())
To drill into one submission, request it by accession number: GET /v1/fnd/stocks/AAPL/filings/{accession} returns that filing's metadata. That's the drill-down your UI or audit trail points at.
The same API key covers the rest of the fundamentals family (XBRL financials, ratios, insider transactions, 13F holdings) and the other asset classes; the fundamentals overview maps what sits behind the filings layer.
What building this on EDGAR directly costs#
EDGAR is public and free, and for a one-off download it's the right tool. A production pipeline against it is a different job. The raw listing interface is index files: daily and quarterly indexes that enumerate submissions in fixed-width and pipe-delimited text, which you download, parse, and merge into your own filings table. There's no query interface over them in the shape above; "all 10-Ks for this CIK since 2020" is a filter you build and maintain yourself.
The SEC's fair access policy also applies: automated clients are expected to declare an identifying User-Agent and stay under the published request rate (ten requests per second at the time of writing), and traffic that ignores this gets blocked. None of this is hard on day one. The cost is the ongoing kind: polling schedules, format drift, amendment handling, retry logic, and a parser someone has to own after the person who wrote it moves on. A keyed API request that returns accession number, filing date, and form type replaces that maintenance surface with one HTTP call, and rate limits become explicit response headers (X-RateLimit-Remaining, Retry-After on a 429) instead of a blocked IP.
Common pitfalls#
CIK leading zeros disappear. The CIK is a ten digit zero-padded string, and any pipeline that passes it through an integer column or a spreadsheet turns 0000320193 into 320193. The join against a system expecting the padded form then fails, often silently as a no-match rather than an error. Store CIKs as strings from the first hop.
Exact form filters skip amendments. A 10-K/A is an amended 10-K that supersedes the original, and a filter matching the literal string "10-K" won't return it. Decide a policy up front: if your feature answers "what did the company most recently report", you want amendments; if it answers "what was known on the original filing date", you don't. Either way, make it a decision rather than an accident of string matching.
Filing date is not period date. An 8-K filed in January can report a December event, and a 10-K's filing date lags the fiscal year end by weeks. Companies also end fiscal years in different months, so "each company's latest 10-K" can cover periods a quarter or more apart. Sort by filing date for recency of disclosure; for fiscal comparisons, read the reporting period out of the filing itself.
The path in one pass#
Ticker to CIK is one profile call, and the filings list is a second, with every returned row traceable to an exact submission by accession number and filing date. That's the whole integration: an afternoon of wiring instead of an index-file parser with your name on the maintenance rota. The free tier is enough to build against; see pricing when you're ready to size a production quota.


