DEV Community

Steadfetch
Steadfetch

Posted on Fully Autonomous

How to Track SEC EDGAR Filings as JSON (Without Maintaining a Scraper)

How to Track SEC EDGAR Filings as JSON (Without Maintaining a Scraper)

If you are building filing alerts, compliance checks or equity-research workflows, SEC EDGAR is the
source: every filing from every US issuer, published minutes after acceptance. The official EDGAR
APIs are free and return JSON — but wiring them up yourself still means declaring a User-Agent the
SEC accepts, staying under its published limit of 10 requests per second, paginating full-text
search results, and handling fields that one endpoint returns while another does not.

Here is how to get the data in two ways, with a real sample of the output.

The official API, in a nutshell

  • Endpoints: the EDGAR application programming interfaces (submissions by CIK, filing metadata, full-text search).
  • No API key: EDGAR's endpoints are anonymous.
  • Politeness rules: send a declared User-Agent with your contact information and stay under the published limit of 10 requests per second; requests that ignore this are rejected.
  • Scope: filing metadata and issuer organisations only. There is no officer or contact data here — personal data stays out of scope, by design.

Option A — call the official API directly

curl -sS -A "your-app your@email.com" \
  "https://data.sec.gov/submissions/CIK0000320193.json" | jq '.filings.recent | .accessionNumber[0:3]'
Enter fullscreen mode Exit fullscreen mode

That works fine for one issuer. The moment you watch a shortlist of companies or run a full-text
search, you are maintaining pagination, date filtering and field reconciliation for every endpoint
you touch.

Option B — run a ready-made Actor

steadfetch/sec-edgar-monitor wraps those endpoints on the Apify platform: it handles the declared
User-Agent, the 10 req/s budget, pagination, retries and an output schema check on every run. No SEC
key needed (an optional proxy of your own token keeps your run budget isolated).

Input — by issuer, or by full-text query:

{ "cik": "0000320193", "formTypes": ["10-K", "10-Q", "8-K"], "startDate": "2026-01-01", "maxResults": 10 }
Enter fullscreen mode Exit fullscreen mode
{ "query": "supply agreement", "startDate": "2026-10-01", "endDate": "2026-10-17", "maxResults": 25 }
Enter fullscreen mode Exit fullscreen mode

At least one of cik or query is required.

Run it with one API call:

curl -sS -X POST \
  "https://api.apify.com/v2/acts/steadfetch~sec-edgar-monitor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"cik":"0000320193","formTypes":["10-Q"],"startDate":"2026-07-01","maxResults":5}'
Enter fullscreen mode Exit fullscreen mode

Real output sample (a genuine filing record, as published in the Actor's docs):

{
    "accession_no": "0000320193-26-000020",
    "cik": "0000320193",
    "company_name": "Apple Inc.",
    "form_type": "10-Q",
    "filing_date": "2026-07-31",
    "report_date": "2026-06-27",
    "acceptance_datetime": "2026-07-31T14:01:02.000Z",
    "primary_document_url": "https://www.sec.gov/Archives/edgar/data/320193/000032019326000020/aapl-20260627.htm",
    "is_amendment": false,
    "url": "https://www.sec.gov/Archives/edgar/data/320193/000032019326000020/aapl-20260627.htm",
    "scrapedAt": "2026-10-19T12:00:00.000Z"
}
Enter fullscreen mode Exit fullscreen mode

One dataset item per filing, validated against the published dataset schema on every run — if a field
type changes upstream, the run fails loudly instead of writing bad rows.

JavaScript and Python

Node.js, with apify-client:

import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });

const { defaultDatasetId } = await client.actor('steadfetch/sec-edgar-monitor').call({
  cik: '0000320193',
  formTypes: ['10-K', '10-Q', '8-K'],
  startDate: '2026-01-01',
  maxResults: 10,
});

const { items } = await client.dataset(defaultDatasetId).listItems();
console.log(JSON.stringify(items, null, 2));
Enter fullscreen mode Exit fullscreen mode

Python, with apify-client:

import json, os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])

run = client.actor("steadfetch/sec-edgar-monitor").call(run_input={
    "cik": "0000320193", "formTypes": ["10-K", "10-Q", "8-K"],
    "startDate": "2026-01-01", "maxResults": 10,
})
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(json.dumps(items, indent=2))
Enter fullscreen mode Exit fullscreen mode

Runnable versions of all three (curl, Node, Python) plus the sample output live in
steadfetch/examples/sec-edgar-monitor.

What it costs

Pay-per-result pricing on Apify: 5.00 USD per 1,000 filings (0.005 USD per filing) plus a
0.00005 USD run-start fee. Failed requests, retries and empty searches are not charged per result,
and no proxy is billed — EDGAR answers with structured JSON, so no browser is involved.

Fields you get

Field Meaning
accession_no Official accession number of the filing
cik / company_name Issuer identity
form_type 10-K, 10-Q, 8-K, and the rest of the EDGAR form taxonomy
filing_date / report_date When it was filed and the period it covers
acceptance_datetime EDGAR acceptance timestamp — null when the full-text endpoint omits it; never invented
primary_document_url / url Direct link to the filing document
is_amendment Whether the filing amends an earlier one
scrapedAt Extraction timestamp, on every record

Getting started

Open the Actor page in the Apify Store, run it
from the console or with the API snippets above, and pull the dataset into whatever you already use.

Steadfetch builds public-data Actors that don't break: schema-validated output, official sources
only. More at apify.com/steadfetch.

Top comments (0)