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-Agentwith 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]'
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 }
{ "query": "supply agreement", "startDate": "2026-10-01", "endDate": "2026-10-17", "maxResults": 25 }
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}'
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"
}
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));
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))
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)