SEC Filing API for AI Agents
Resolve CIKs, retrieve submissions and XBRL facts, validate provenance, and return source-backed agent answers.

Featured Providers & Official Sources
Verify endpoint coverage, fields, freshness, entitlements, and licensing before production use.
Decision brief
TL;DR
Resolve the company to a zero-padded CIK, then use the Submissions API for forms, accession numbers, filing dates, report dates, primary documents, and filing history.
The filing HTML, exhibits, and complete submission files provide narrative disclosures and the primary evidence an agent should cite.
Company Facts, Company Concept, and Frames make numeric disclosures easier to query, but units, periods, forms, and taxonomy context must remain attached.
Return accession, form, dates, source URL, and document hash with extracted evidence. Label summaries, comparisons, and risk conclusions as model inference.
Who this guide is for and what you need
This is for teams building filing research, risk-factor comparison, event monitoring, earnings preparation, financial extraction, or compliance assistants. It assumes a trusted backend, persistent storage, an HTML/XBRL parser, and a retrieval or citation layer.
SEC EDGAR data sources: choose the right endpoint
| Source | Best for | Key fields | Main limitation |
|---|---|---|---|
| company_tickers.json | Ticker/name to CIK resolution | cik_str, ticker, title | Entity matching still needs validation |
| Submissions API | Filing history and metadata | form, accession, filed, reportDate, primaryDocument | Recent records are columnar; older history may be in extra files |
| Archives | Primary documents, exhibits, full submission text | HTML, text, XML, XBRL artifacts | Parsing varies by filing and era |
| Company Facts | All normalized company concepts in one response | taxonomy, tag, label, units, facts | Not a substitute for narrative disclosure |
| Company Concept | One concept across filings | units, val, accn, fy, fp, form, filed, frame | Custom concepts may not be comparable |
| Frames | Cross-company facts aligned to a calendar frame | taxonomy, tag, unit, period, entity facts | Fiscal calendars may not align exactly |
Do not confuse APIs: public data retrieval on data.sec.gov is different from EDGAR Next filer APIs used to submit filings and manage filer accounts.
Evidence-first filing agent architecture
Keep acquisition, normalization, retrieval, and generation separate. The model should not invent URLs, accession numbers, dates, or units; those belong to deterministic services.
- Acquisition: polite HTTP client, cache, retry, conditional fetch, bulk downloads when appropriate.
- Raw evidence store: exact bytes, response headers, retrieval time, source URL, SHA-256 hash.
- Normalized filing record: CIK, accession, form, filing date, report date, primary document, amendment relationship.
- Document layer: cleaned sections, tables, exhibits, inline XBRL and character offsets back to source.
- Agent layer: retrieval filters, bounded context, citations, inference labels and refusal when evidence is insufficient.
Step 1: resolve ticker, company name, and CIK
EDGAR is organized around CIK, not ticker. Normalize the ticker, match it against the SEC mapping, confirm the legal entity name and exchange, and store the ten-digit zero-padded CIK for API requests. Never reuse a ticker mapping indefinitely: tickers and corporate identities can change.
import requests
HEADERS = {"User-Agent": "FilingAgent/1.0 research@example.com"}
rows = requests.get(
"https://www.sec.gov/files/company_tickers.json",
headers=HEADERS,
timeout=20,
).json().values()
def resolve_ticker(symbol: str):
symbol = symbol.upper().strip()
row = next(x for x in rows if x["ticker"].upper() == symbol)
return {
"ticker": row["ticker"],
"company": row["title"],
"cik": str(row["cik_str"]).zfill(10),
}Step 2: query Submissions and select the filing
The recent filing arrays are columnar: values at the same index belong to one filing. Zip only known columns, filter by form and filing date, and retain both the filing date and report date. Include amendments deliberately instead of dropping every /A suffix.
def recent_filings(cik: str):
url = f"https://data.sec.gov/submissions/CIK{cik}.json"
payload = requests.get(url, headers=HEADERS, timeout=20).json()
recent = payload["filings"]["recent"]
keys = ["accessionNumber", "filingDate", "reportDate",
"form", "primaryDocument", "primaryDocDescription"]
return [dict(zip(keys, values)) for values in zip(*(recent[k] for k in keys))]
filing = next(
f for f in recent_filings("0000320193")
if f["form"] in {"10-K", "10-Q", "8-K"}
)Step 3: reconstruct and preserve the filing document URL
An accession number identifies an accepted submission. Remove dashes only for the Archives directory, keep the original accession for citation, and combine it with the integer CIK and primary-document filename. Store the URL before parsing so every extracted passage can trace back to the exact document.
def filing_url(cik: str, filing: dict) -> str:
cik_integer = str(int(cik))
accession_path = filing["accessionNumber"].replace("-", "")
document = filing["primaryDocument"]
return (
"https://www.sec.gov/Archives/edgar/data/"
f"{cik_integer}/{accession_path}/{document}"
)
source_url = filing_url("0000320193", filing)Step 4: use XBRL facts without losing context
A numeric value is not meaningful by itself. Preserve taxonomy, concept, unit, start/end or instant date, fiscal year, fiscal period, form, filed date, accession, frame, and whether the fact was later repeated or amended. Prefer comparable standard-taxonomy facts, but fall back to the filing document for custom extensions and narrative context.
facts_url = "https://data.sec.gov/api/xbrl/companyfacts/CIK0000320193.json"
company_facts = requests.get(facts_url, headers=HEADERS, timeout=20).json()
revenue = company_facts["facts"]["us-gaap"]["RevenueFromContractWithCustomerExcludingAssessedTax"]
usd_facts = revenue["units"]["USD"]
annual = [x for x in usd_facts if x.get("form") == "10-K" and x.get("fp") == "FY"]
for fact in annual[-3:]:
print(fact["val"], fact["fy"], fact["filed"], fact["accn"], fact.get("frame"))End-to-end implementation pattern
The production path should be deterministic until the evidence bundle is complete. Let the model choose a research intent or requested section, but keep identity resolution, filing selection, URL construction, parsing, hashing, and validation in code.
| Stage | Deterministic service | Model role | Stored evidence |
|---|---|---|---|
| Resolve | Ticker/name to CIK mapping | Clarify ambiguous entity | CIK, company, mapping timestamp |
| Select | Form/date/accession filters | Translate user intent into filters | form, filed, report date, accession |
| Acquire | HTTP fetch, cache, hash | None | URL, bytes, headers, retrievedAt, hash |
| Parse | DOM/XBRL/table parser | Optional section classification | section, offsets, tables, concepts |
| Answer | Citation builder and policy checks | Summarize, compare, explain uncertainty | claims, evidence IDs, prompt/model version |
Normalize one filing evidence contract
{
"entity": {"cik":"0000320193","ticker":"AAPL","name":"Apple Inc."},
"filing": {
"form":"10-K","accession":"0000320193-25-000079",
"filed":"2025-10-31","report_date":"2025-09-27",
"primary_document":"aapl-20250927.htm","source_url":"https://www.sec.gov/..."
},
"evidence": [{
"section":"Risk Factors","text":"bounded extracted passage",
"source_url":"https://www.sec.gov/...","document_sha256":"...",
"retrieved_at":"2026-07-31T09:00:00Z"
}],
"answer_policy": {"cite_every_claim":true,"label_inference":true}
}Keep the raw SEC field names in a source payload or provenance record even if your application uses normalized names. This makes audits and parser upgrades possible without re-downloading everything.
Validation checklist before the agent answers
Fair access, caching, cost, and latency controls
SEC guidance currently limits automated access to no more than ten requests per second in total and asks applications to identify themselves. Treat ten as a ceiling, not a target. Use a descriptive User-Agent, cache immutable filing documents, prefer bulk ZIP data for large backfills, use bounded concurrency, and implement exponential backoff for 403, 429, and transient 5xx responses.
- Cache ticker mapping and Submissions responses briefly; cache accession documents by content hash for much longer.
- Poll filing metadata rather than repeatedly downloading the same full documents.
- Use nightly bulk archives for complete-history ingestion instead of millions of individual requests.
- Set connect/read timeouts, a retry budget, circuit breaking, and a dead-letter queue.
- Limit chunks, tables, exhibits, and XBRL facts sent to the model to control token cost and prompt-injection exposure.
Common failure modes and troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
| 403 or blocked requests | Missing User-Agent, excessive or bursty traffic | Identify the app, throttle globally, cache, back off |
| Wrong company | Ticker reuse, symbol normalization, name ambiguity | Confirm CIK and legal entity before retrieval |
| Missing older filings | Only recent columnar data was read | Follow additional files or ingest submissions.zip |
| Revenue values disagree | Different units, periods, forms, concepts, or amendments | Compare full XBRL context and accession |
| Risk section extraction is empty | Heading variation, inline XBRL markup, document era | Use DOM-aware parsing, form templates, and fallback text |
| Agent cites the wrong period | Filing date confused with report date or fiscal frame | Carry all dates through retrieval and answer templates |
How to evaluate a filing-aware AI agent
Measure retrieval and evidence separately from writing quality. A fluent answer with the wrong accession or period is a failed answer.
QVeris implementation pattern for filing research
A QVeris-based agent can Discover filing or financial capabilities by intent, Inspect parameters and operational statistics, Probe candidate inputs and quote before execution, then Call the selected capability. Keep the SEC accession, source URL, filing dates, and extracted evidence in the application record; use SEC documents as the authoritative source for SEC filing claims.
Recommended loop: Discover → Inspect → Probe → Call → validate accession/source → answer with citations → reconcile usage history.
See the QVeris MCP documentation, QVeris REST API reference, SEC filings analysis agent guide, and SEC filing API comparison.
FAQ
Public data.sec.gov submissions and XBRL APIs do not require a key. Automated access must still identify the application and follow SEC fair-access guidance.
Submissions provides filing identity and history. Company Facts provides normalized XBRL concepts and units across filings.
Resolve ticker to CIK, select an accession and primary document from Submissions, remove accession dashes for the Archives path, and retain the original accession for citation.
SEC guidance currently sets a total ceiling of ten requests per second. Run below that ceiling, cache aggressively, and back off on errors.
No. Numeric facts do not replace narrative disclosures, exhibits, custom taxonomy context, or the source filing.
Preserve form, accession, dates, amendment status, and original source. Never silently overwrite the original filing.
Require accession-linked evidence, validate dates and units, cite bounded passages, and label all model inference.
QVeris helps discover, inspect, probe, and call relevant capabilities; SEC documents remain authoritative for filing claims.
