Specialist research. Published by Synoptic.
Sources & methodology

Python quickstart

Read SEC submissions in Python with a real response

A submissions response stores recent filing fields as parallel arrays. Convert them by position and validate their lengths before building rows.

Run the example

Save the script as submissions_example.py. For a live request set SEC_USER_AGENT to your organization and a monitored contact address, then run python3 submissions_example.py. There is no SEC API key to configure.

For offline reproduction, save a submissions response and pass its path: python3 submissions_example.py company.json. The publication check used the real Apple submissions response from 2026-11-14. It successfully parsed the saved response and selected filing rows; the linked primary documents were not downloaded.

python
"""python3 submissions_example.py SNAPSHOT.json; optional live request with SEC_USER_AGENT."""
import json
import os
import re
import sys
from urllib.parse import quote
from urllib.request import Request, urlopen

def filing_rows(payload):
    recent = payload["filings"]["recent"]
    fields = ("accessionNumber", "form", "filingDate", "primaryDocument")
    n = len(recent["accessionNumber"])
    if any(len(recent[name]) != n for name in fields):
        raise ValueError("Unequal SEC column lengths")
    cik = str(int(payload["cik"]))
    for i in range(n):
        row = {name: recent[name][i] for name in fields}
        accession = row["accessionNumber"]
        if not re.fullmatch(r"\d{10}-\d{2}-\d{6}", accession):
            raise ValueError("Invalid accession")
        row["url"] = f"https://www.sec.gov/Archives/edgar/data/{cik}/{accession.replace('-', '')}/{quote(row['primaryDocument'], safe='')}"
        yield row

if __name__ == "__main__":
    if len(sys.argv) > 1:
        with open(sys.argv[1]) as handle:
            payload = json.load(handle)
        mode = "saved SEC response"
    else:
        agent = os.environ["SEC_USER_AGENT"]  # Organization + monitored contact address.
        request = Request("https://data.sec.gov/submissions/CIK0000320193.json", headers={"User-Agent": agent})
        with urlopen(request, timeout=30) as response:
            payload = json.load(response)
        mode = "live SEC response"
    rows = list(filing_rows(payload))
    forms = [r for r in rows if r["form"] in {"10-K", "10-Q", "8-K"}]
    print(json.dumps({"mode": mode, "company": payload["name"], "parsed_rows": len(rows), "selected_examples": forms[:3], "older_history_files": payload["filings"].get("files", []), "limits": "Lists metadata only; linked documents were not fetched or parsed by this example."}, indent=2))

Executed against a saved HTTP 200 SEC response on 2026-11-14. The script uses only the Python standard library. A new live request may return different filings.

Examples from the saved response

These rows were selected from the saved SEC response, not typed as hypothetical filings. They are a snapshot of filing metadata. The links are deterministically constructed from that metadata and have not been independently fetched in this example.

8-K2026-11-090001140361-26-042798SEC document
10-K2026-11-030000320193-26-000026SEC document
8-K2026-11-020000320193-26-000024SEC document

Avoid turning this into an uncontrolled crawler

The SEC developer guidance caps access at ten requests per second across a user’s machines. That is a ceiling, not a suggested polling target. Cache a company response, coordinate workers and back off when the service returns rate-limit or blocking responses.

For older history, follow the filenames under filings.files; filings.recent alone is not the full lifetime archive. For a market-wide rebuild use the bulk archives rather than iterating every company at high frequency.

Keep this boundary explicit

The script returns primary filing metadata and a URL. It does not parse an 8-K item, extract financial tables, identify every exhibit or judge the meaning of a disclosure. Those are separate document-processing tasks with their own evidence checks.

Source notes

  1. SEC EDGAR API documentation ↗

    Official submissions, XBRL, bulk data, update schedule and access requirements.

  2. SEC Developer Resources ↗

    Official archive, index and RSS options; fair-access request limit.

The Synoptic workflow

Explore the SEC event stream

For new-filing monitoring, verify the stream and your account access.

Explore the SEC event stream