QVeris
Research, Compliance & Risk

SEC Filing API for AI Agents

Resolve CIKs, retrieve submissions and XBRL facts, validate provenance, and return source-backed agent answers.

Published: March 27, 2026 · By the QVeris Team

SEC Filing API for AI Agents financial research workflow
Financial research context for SEC Filing API for AI Agents; illustrative workflow image, not a product interface.

Decision brief

TL;DR

Use Submissions for filing identity

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.

Use Archives for the source document

The filing HTML, exhibits, and complete submission files provide narrative disclosures and the primary evidence an agent should cite.

Use XBRL APIs for normalized facts

Company Facts, Company Concept, and Frames make numeric disclosures easier to query, but units, periods, forms, and taxonomy context must remain attached.

Separate fact from inference

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.

Identity: application name and contact email for User-Agent
Storage: raw response, normalized record, content hash
Parser: HTML, inline XBRL, tables, exhibits
Agent contract: citations, uncertainty, no unsupported claims

SEC EDGAR data sources: choose the right endpoint

SourceBest forKey fieldsMain limitation
company_tickers.jsonTicker/name to CIK resolutioncik_str, ticker, titleEntity matching still needs validation
Submissions APIFiling history and metadataform, accession, filed, reportDate, primaryDocumentRecent records are columnar; older history may be in extra files
ArchivesPrimary documents, exhibits, full submission textHTML, text, XML, XBRL artifactsParsing varies by filing and era
Company FactsAll normalized company concepts in one responsetaxonomy, tag, label, units, factsNot a substitute for narrative disclosure
Company ConceptOne concept across filingsunits, val, accn, fy, fp, form, filed, frameCustom concepts may not be comparable
FramesCross-company facts aligned to a calendar frametaxonomy, tag, unit, period, entity factsFiscal 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.

RESOLVE CIK
FETCH METADATA
GET DOCUMENT
PARSE + CHUNK
VALIDATE
ANSWER + CITE
  • 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.

Python · ticker to CIK
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.

Python · normalize recent filings
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.

Python · SEC Archives URL
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.

Python · inspect Company Facts
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.

StageDeterministic serviceModel roleStored evidence
ResolveTicker/name to CIK mappingClarify ambiguous entityCIK, company, mapping timestamp
SelectForm/date/accession filtersTranslate user intent into filtersform, filed, report date, accession
AcquireHTTP fetch, cache, hashNoneURL, bytes, headers, retrievedAt, hash
ParseDOM/XBRL/table parserOptional section classificationsection, offsets, tables, concepts
AnswerCitation builder and policy checksSummarize, compare, explain uncertaintyclaims, evidence IDs, prompt/model version

Normalize one filing evidence contract

JSON · evidence bundle
{
  "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

Entity: CIK, legal name, ticker mapping confirmed
Identity: accession and primary document match Submissions
Dates: filing date and report period are not confused
Form: amendment, exhibit, and form family handled explicitly
Facts: taxonomy, unit, duration/instant, frame preserved
Document: source URL loads and content hash is stored
Claims: every material statement maps to evidence
Inference: analysis is labeled and uncertainty is visible

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

SymptomLikely causeFix
403 or blocked requestsMissing User-Agent, excessive or bursty trafficIdentify the app, throttle globally, cache, back off
Wrong companyTicker reuse, symbol normalization, name ambiguityConfirm CIK and legal entity before retrieval
Missing older filingsOnly recent columnar data was readFollow additional files or ingest submissions.zip
Revenue values disagreeDifferent units, periods, forms, concepts, or amendmentsCompare full XBRL context and accession
Risk section extraction is emptyHeading variation, inline XBRL markup, document eraUse DOM-aware parsing, form templates, and fallback text
Agent cites the wrong periodFiling date confused with report date or fiscal frameCarry 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.

Entity accuracy: correct CIK and filer
Filing accuracy: correct form, accession, amendment, dates
Retrieval recall: relevant sections, exhibits, facts found
Citation precision: cited passage supports the claim
Numeric integrity: value, unit, period, concept preserved
Inference discipline: fact, calculation, and opinion distinguished

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.

FAQ

Does the SEC EDGAR API require a key?

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 vs Company Facts?

Submissions provides filing identity and history. Company Facts provides normalized XBRL concepts and units across filings.

How do I build a filing URL?

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.

What request rate should I use?

SEC guidance currently sets a total ceiling of ten requests per second. Run below that ceiling, cache aggressively, and back off on errors.

Can I rely only on Company Facts?

No. Numeric facts do not replace narrative disclosures, exhibits, custom taxonomy context, or the source filing.

How should amendments be handled?

Preserve form, accession, dates, amendment status, and original source. Never silently overwrite the original filing.

How do I reduce hallucinations?

Require accession-linked evidence, validate dates and units, cite bounded passages, and label all model inference.

Where does QVeris fit?

QVeris helps discover, inspect, probe, and call relevant capabilities; SEC documents remain authoritative for filing claims.

Official sources