SEC EDGAR API — Filings, XBRL Financials & Full-Text Search avatar

SEC EDGAR API — Filings, XBRL Financials & Full-Text Search

Pricing

from $0.18 / 1,000 filing records

Go to Apify Store
SEC EDGAR API — Filings, XBRL Financials & Full-Text Search

SEC EDGAR API — Filings, XBRL Financials & Full-Text Search

Query the SEC's official EDGAR APIs from one Actor: resolve any ticker, CIK or company name; list 10-K, 10-Q, 8-K and Form 4 filings by date; pull normalized XBRL income statement, balance sheet and cash flow by period; run full-text search across filings since 2001. No API key.

Pricing

from $0.18 / 1,000 filing records

Rating

0.0

(0)

Developer

Insight Solutions

Insight Solutions

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

9 hours ago

Last modified

Share

Get SEC filings and financials by ticker or CIK, as clean JSON, with no API key. Give it AAPL, 320193 or Apple Inc. and get back the company record, the 10-K / 10-Q / 8-K / Form 4 filing history, a normalized income statement, balance sheet and cash flow built from XBRL, or full-text search hits across filing documents.

Every request goes to the SEC's own public JSON APIs — data.sec.gov, www.sec.gov and efts.sec.gov — so the data is EDGAR's, live, and no scraping or login is involved. Filings appear within minutes of acceptance. From $0.0003 per filing record, and diagnostic rows are free.

Most SEC Actors cover exactly one slice: Form D only, Form 4 only, financials only. This one covers all four in a single, consistent interface — which is what makes it useful to an agent that does not know in advance what it will need.

Try it in 30 seconds

The five most recent Apple annual reports:

{
"mode": "filings",
"identifiers": ["AAPL"],
"formTypes": ["10-K"],
"maxFilingsPerCompany": 5,
"userAgentContact": "Acme Research data@acme.com"
}

Set userAgentContact to your own organisation and a working address. The SEC requires every automated request to say who is making it and answers HTTP 403 otherwise. The Console example is pre-filled with the publisher's contact so the sample run works out of the box; replace it with yours for real use, so the SEC reaches you, not us, about your traffic. Runs with an empty or placeholder contact stop with an explanatory row and are not charged.

Output — one row per filing (or per company, or per statement × fiscal period); the fields you will use most are cik, companyName, formType, filingDate, documentUrl (full list under Output reference). Anything that could not be fetched comes back as a free diagnostic row (ok: false, errorType, error) instead of a charge, and every run ends with one free summary row saying what it did.

{ "ok": true, "cik": "320193", "companyName": "Apple Inc.", "formType": "10-K", "filingDate": "2024-11-01", "documentUrl": "https://www.sec.gov/Archives/edgar/data/320193/000032019324000123/aapl-20240928.htm" }

Price — $0.30 per 1,000 filing records on the FREE tier (+ $0.0005 per run that returns a row); company records are $0.50 per 1,000, financial periods $0.40 per 1,000, and diagnostic rows are free. Pay-per-event, no API key, no browser, limited permissions — works over the Apify MCP server (mcp.apify.com) and with agentic (x402) payments.

From code — client.actor("insight.solutions/sec-edgar-api").call(run_input={…}) with apify-client, or POST https://api.apify.com/v2/acts/insight.solutions~sec-edgar-api/run-sync-get-dataset-items.

ModeGive itGet backCharged as
companytickers / CIKs / namesOne entity record per company: SIC code, exchanges, addresses, fiscal year end, former namescompany-record
filingsidentifiers + optional form and date filtersOne row per filing, with direct links to the primary document and the filing indexfiling-record
financialsidentifiersOne row per statement per fiscal period, with normalized concepts and source XBRL tagsfinancial-period
fullTextSearcha search phrase, optionally scoped to companies, forms and datesOne row per matching filing document, with a highlighted snippetfiling-record

More examples:

{ "mode": "financials", "identifiers": ["MSFT"], "statements": ["income", "cashflow"], "periodType": "annual", "maxPeriods": 4 }
{ "mode": "fullTextSearch", "query": "\"material weakness\"", "formTypes": ["10-K"], "filedAfter": "2023-01-01", "maxFilingsPerCompany": 50 }
{ "mode": "filings", "identifiers": ["TSLA", "NVDA", "AMD"], "formTypes": ["8-K"], "filedAfter": "2024-01-01", "maxFilingsPerCompany": 200 }

Use cases

  • Pull 10-K and 10-Q financials by ticker into a model or spreadsheet — revenue, gross profit, operating income, net income, EPS, free cash flow, per fiscal period.
  • Build a filings alert feed — filings mode with formTypes: ["8-K"] and filedAfter set to your last check, on an Apify Schedule.
  • Search the text of SEC filings for a phrase — "material weakness", "going concern", a product name — across every filer since 2001, then follow documentUrl to the source.
  • Screen companies before a deal or an investment — company mode returns SIC code, exchanges, fiscal year end and former names for a whole ticker list in one run.
  • Ground an LLM or research agent in primary sources — every row carries source, sourceUrl and, for financials, the exact XBRL tag behind each number.
  • Track insider and ownership filings — Form 4 and Form D are just formTypes values.

How it compares

  • Four modes, one Actor. Company resolution, filing history, normalized financials and full-text search behind one input schema, instead of four listings that each do one.
  • XBRL that is actually normalized. US-GAAP tagging is inconsistent between filers and across years. Each field is filled from a documented fallback chain of tags, and rawConcepts records exactly which tag, filing and date produced each number — so nothing is hidden and nothing is unauditable.
  • Complete filing history, not a silent truncation. Large filers keep only their most recent ~1,000 filings in the main submissions file; the rest live in overflow pages. This Actor walks up to five of those per company, skipping any whose date window cannot match, so a request for older filings gets real answers.
  • Any identifier resolves. AAPL, 320193, 0000320193 and Apple Inc. all land on the same company. Multi-class tickers (GOOG / GOOGL) resolve to one CIK and are returned once, so you are charged once.
  • Charge-on-success, and a named cause. An identifier that does not resolve, a filter matching no filings, an SEC outage — all produce free diagnostic rows. A run whose input was usable but that returns nothing — a ticker that does not exist, a filter that matches no filings, the SEC refusing or failing us — finishes SUCCEEDED with zero results, with a status message that says so and names the cause. Such a run costs nothing, start fee included — and if the SEC refused us, the status says which of its two refusals it hit, its rate threshold or its undeclared-tool check, because those need opposite responses. A run finishes FAILED only when the Actor itself hit an error.

Input reference

FieldTypeDefaultApplies toNotes
modestringfilingsallcompany, filings, financials, or fullTextSearch
identifiersarray["AAPL"]allTickers, CIKs (padded or not), or company names. Required except in fullTextSearch, where it narrows the search
formTypesarrayall formsfilings, fullTextSearche.g. ["10-K","10-Q","8-K","4","D"]. Asking for 10-K also returns 10-K/A, flagged with isAmendment
filedAfter / filedBeforedate—filings, fullTextSearchInclusive bounds on filing date, YYYY-MM-DD
maxFilingsPerCompanyinteger50filings, fullTextSearchFilings per company, newest first. In fullTextSearch it caps total hits. Max 1000
statementsarrayall threefinancialsAny of income, balance, cashflow. One row per statement per period
periodTypestringannualfinancialsannual, quarterly, or both
maxPeriodsinteger8financialsPeriods per company, most recent first. With both, applies to each separately. Max 40
querystring—fullTextSearchRequired. Wrap a phrase in double quotes for an exact match
includeDocumentUrlsbooleantruefilings, fullTextSearchInclude links to the primary document and the filing index page
userAgentContactstring—allRequired in practice. Your organisation and a working contact address
maxRunSecsinteger240allWall-clock budget. The Actor stops asking for more data when reached, keeps everything written, and says so. Min 30, max 3600

Output reference

Every row carries ok, source, sourceUrl and scrapedAt. Rows where ok is false are diagnostics and are never charged; errorType says which kind of problem it was (unresolved-identifier, no-results, not-found, invalid-input, budget-exhausted, time-budget, or an upstream class: rate-limited, user-agent-rejected, forbidden, network, http, parse, upstream-shape).

Every run also ends with one free summary row, rowType: "run-summary" — never charged, and easy to drop with a single test. It reports rowsWritten, diagnosticRows, secRequests, elapsedSecs, whether the time or charge budget stopped the run, and — the reason it exists — secAccessIssue, which is null, "rate-limited" or "user-agent-rejected". Those last two are the only two ways the SEC refuses a client, and they need opposite responses: wait a few minutes, or fix your contact string.

{ "ok": true, "rowType": "run-summary", "mode": "filings", "rowsWritten": 5, "diagnosticRows": 0,
"secRequests": 2, "secAccessIssue": null, "rateLimitedResponses": 0, "userAgentRejectedResponses": 0,
"requestsPerSecondCeiling": 8, "elapsedSecs": 0.7, "summary": "5 row(s) written in 0.7s · 2 SEC request(s)" }

filings — cik, companyName, accessionNumber, formType, baseFormType, isAmendment, filingDate, reportDate, acceptanceDateTime, primaryDocument, primaryDocDescription, documentUrl, filingIndexUrl, size, isXBRL, isInlineXBRL, items.

company — cik, cikPadded, ticker, tickers, name, sic, sicDescription, entityType, exchanges, fiscalYearEnd, category, ein, stateOfIncorporation, phone, businessAddress, mailingAddress, formerNames, matchedOn, matchedInputs.

fullTextSearch — accessionNumber, cik, companyName, tickerFromDisplayName, formType, filingDate, periodEnding, snippet, documentUrl.

financials — one row per statement per period:

{
"ok": true,
"cik": "320193", "companyName": "Apple Inc.",
"statement": "income", "periodType": "annual",
"fiscalYear": 2024, "fiscalPeriod": "FY", "fiscalLabelSource": "sec-fy-fp",
"periodStart": "2023-10-01", "periodEnd": "2024-09-28", "periodDays": 363,
"unit": "USD",
"revenues": 391035000000,
"costOfRevenue": 210352000000,
"grossProfit": 180683000000,
"operatingIncome": 123216000000,
"netIncome": 93736000000,
"eps": 6.08,
"rawConcepts": {
"revenues": {
"tag": "RevenueFromContractWithCustomerExcludingAssessedTax",
"value": 391035000000, "unit": "USD",
"accn": "0000320193-24-000123", "form": "10-K", "filed": "2024-11-01"
}
},
"source": "data.sec.gov",
"scrapedAt": "2026-09-08T06:55:41.000Z"
}

How the XBRL is normalized

Each normalized field is filled from the first US-GAAP tag in its chain that has a value for the period; rawConcepts always records which tag was used.

StatementFieldsExample tag chains
incomerevenues, costOfRevenue, grossProfit, operatingExpenses, researchAndDevelopment, operatingIncome, incomeBeforeTax, incomeTaxExpense, netIncome, eps, epsBasic, weightedAverageSharesDilutedrevenues: RevenueFromContractWithCustomerExcludingAssessedTax → …IncludingAssessedTax → Revenues → SalesRevenueNet → SalesRevenueGoodsNet → RevenuesNetOfInterestExpense. grossProfit: GrossProfit, else computed as revenues − costOfRevenue. netIncome: NetIncomeLoss → ProfitLoss → NetIncomeLossAvailableToCommonStockholdersBasic
balancetotalAssets, currentAssets, totalLiabilities, currentLiabilities, stockholdersEquity, cashAndEquivalents, shortTermInvestments, inventory, longTermDebttotalLiabilities: Liabilities, else liabilitiesAndEquity − stockholdersEquity. cashAndEquivalents: CashAndCashEquivalentsAtCarryingValue → CashCashEquivalentsRestrictedCash…
cashflowoperatingCashFlow, investingCashFlow, financingCashFlow, capitalExpenditures, depreciationAndAmortization, dividendsPaid, shareRepurchases, freeCashFlowcapitalExpenditures: PaymentsToAcquirePropertyPlantAndEquipment → PaymentsToAcquireProductiveAssets. freeCashFlow: computed as operatingCashFlow − capitalExpenditures

Four rules make these numbers trustworthy:

  1. Units are never mixed. Money comes from USD series, EPS from USD/shares, share counts from shares.
  2. Restatements win. When the same period appears in several filings, the most recently filed value is used — a restated figure supersedes the one originally reported.
  3. Annual reports outrank earnings releases. A value from a 10-K or 10-Q is preferred over the same value from an 8-K, even if the 8-K was filed later.
  4. Year-to-date figures are discarded. Six- and nine-month cumulative periods inside 10-Qs are excluded, so a quarterly row is always a single quarter.

Fiscal labelling deserves a note, because it is where most XBRL pipelines go wrong. In the SEC's companyfacts feed, a fact's fy and fp describe the filing it appeared in, not the fact's own period — so FY2022 comparatives sitting inside a FY2024 10-K carry fy: 2024. This Actor cross-references each fact's accession number against the filing's report date and only adopts the SEC's fy/fp when they genuinely describe that period. Where that check cannot be made, the label is derived from the period end and the company's fiscal year end, and fiscalLabelSource tells you which happened.

Pricing

You pay per result, not per minute. There is no subscription and no platform-usage surcharge.

EventWhat triggers itFreeBronzeSilverGold
actor-startOnce per run, only after the first paid row is delivered$0.0005$0.0005$0.0005$0.0005
company-recordEach company profile returned$0.0005$0.0005$0.0005$0.0005
filing-recordEach filing or search hit returned$0.0003$0.0003$0.00024$0.00018
financial-periodEach statement × period returned$0.0004$0.0004$0.00032$0.00024

Bronze is the Starter plan, Silver is Scale, Gold is Business. Higher plans pay less per result.

What that costs in practice

You ask forYou getYou pay
5 Apple 10-Ks5 filing records$0.0005 + 5 × $0.0003 = $0.002
1,000 filings across 20 companies1,000 filing records$0.0005 + 1,000 × $0.0003 = $0.30
4 years of income + cash flow for one company8 financial periods$0.0005 + 8 × $0.0004 = $0.0037
Company profiles for 100 tickers100 company records$0.0005 + 100 × $0.0005 = $0.051

You are never charged for: diagnostic rows — an identifier that does not resolve, a company with no filings matching your filters, an SEC outage; anything at all on a run that returns no paid row — the actor-start fee is billed once, and only right after the first company, filing or financial-period row has been delivered to your dataset, so an SEC outage, an unknown ticker or a filter that matches nothing costs nothing and finishes SUCCEEDED with zero results and a status ending Nothing was charged.; rows the Actor could not write because your run or time budget was exhausted; anything beyond the events above — no platform-usage pass-through.

In financials mode, a company that files with the SEC but publishes no XBRL facts (some foreign private issuers, and anything filed before 2009) returns one company record with financials: null, charged at the company-record rate rather than as a financial period.

Rate limits and the User-Agent requirement

The SEC requires a descriptive User-Agent naming the requester with an address it can reach, and — in its own words — "no more than 10 requests per second, regardless of the number of machines used to submit requests". This Actor sends the userAgentContact you supply on every request and holds the whole run to 8 requests in any rolling second, a deliberate margin under the published ceiling.

"The whole run" is the part worth stating precisely: the limiter is one shared object, not one per fetcher, so no amount of parallel work inside a run can add up past 8 req/s. It is still one run's ceiling. Nothing coordinates across concurrent runs, so several of your own runs in parallel can add up beyond the SEC's limit — another reason the identity in userAgentContact should be yours.

The SEC answers 403 in two different situations, and this Actor never confuses them:

What you getWhat it meansWhat the Actor doesWhat you do
rate-limitedSEC's Request Rate Threshold Exceeded page. Too many requests from your identity or addressSlows the whole run down, pauses every request, retries up to twice on a budget that belongs to the run rather than to each request, then stops and says soRun again in a few minutes; SEC states the block lasts about 10 minutes. Ask for fewer companies per run
user-agent-rejectedSEC's Undeclared Automated Tool page. It did not accept the identity in userAgentContactFails immediately — retrying the same header cannot succeedSet userAgentContact to your organisation and a working contact address

Both produce free diagnostic rows, both are named in the run summary row's secAccessIssue, and when either one leaves the run with no results the run still finishes SUCCEEDED, with a 0 results. status message that says which of the two it was. 429 and 5xx are retried with backoff, honouring Retry-After.

Two budgets bound one run: maxRunSecs (default 240), and a cap of 5 overflow pages per company when walking a large filer's older filings, so a filter that matches nothing costs at most five extra requests instead of downloading an entire history. When either truncates results, the run says so in its status message, its summary row and the log. A rate backoff never spends more than a third of the run's remaining time either — a run that waits out a block returns nothing at all.

Use it from an AI agent, or from code

One JSON input, one flat JSON array out — the shape agent runtimes handle best. No browser, no proxy, no credentials beyond userAgentContact. The Actor is configured for x402 agentic payments: pay-per-event pricing, event-only charging, limited permissions, no Standby mode. It is callable by name over the Apify MCP server, and the Integrations tab pushes results to Slack, a webhook, Zapier, Make, Google Sheets, Snowflake or BigQuery.

curl -X POST "https://api.apify.com/v2/acts/insight.solutions~sec-edgar-api/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"mode":"filings","identifiers":["AAPL"],"formTypes":["10-K"],"maxFilingsPerCompany":5,"userAgentContact":"Acme Research data@acme.com"}'
# pip install apify-client
from apify_client import ApifyClient
client = ApifyClient("<APIFY_TOKEN>")
run = client.actor("insight.solutions/sec-edgar-api").call(run_input={
"mode": "financials",
"identifiers": ["NVDA", "AMD"],
"statements": ["income"],
"periodType": "annual",
"maxPeriods": 3,
"userAgentContact": "Acme Research data@acme.com",
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if row.get("ok"):
print(row["companyName"], row["fiscalYear"], row["revenues"], row["netIncome"])

Agent patterns that work well: answer a question about a company's numbers with financials and a small maxPeriods, citing rawConcepts for the exact XBRL tag; find the source document for a claim with fullTextSearch on a quoted phrase, then follow documentUrl; establish what a company is with company before anything else; watch for new filings with filings, formTypes: ["8-K"] and filedAfter.

FAQ

Why does one of my companies have no financials? XBRL reporting became mandatory in phases starting in 2009, and some filers — notably foreign private issuers filing 20-F or 40-F — are not in the companyfacts feed at all. You get a company record with financials: null instead of an error, charged at the company rate.

A number disagrees with what the company reported. Why? Almost always a restatement. This Actor returns the most recently filed value for each period, which is the current, restated figure — not necessarily the number printed in the original filing. rawConcepts[field].filed and .accn tell you which filing the value came from.

Are amended filings included? Yes. Filtering on 10-K returns both 10-K and 10-K/A; isAmendment and baseFormType separate them. In financials mode, values from original 10-K/10-Q filings are preferred over amendments and over 8-K earnings releases.

Why do GOOG and GOOGL return one row? They are two share classes of one registrant with one CIK. Both resolve to that CIK and it is returned once, with all matched inputs listed in matchedInputs, so you are charged once rather than twice.

How far back does full-text search go? EDGAR's full-text index covers filings from 2001 onwards. For anything older, use filings mode, which reaches back to the beginning of a company's EDGAR history.

Does maxFilingsPerCompany really reach older filings? Yes. The SEC keeps roughly the most recent 1,000 filings in the main submissions file and pushes the rest into overflow pages. The Actor follows those when your limit or date range requires it, and only then — so small requests stay fast. It follows at most five per company; if that truncates your results, the run says so, and narrowing filedAfter/filedBefore takes you straight to the right pages.

When is an empty result a failure, and when is it not? An empty result is never a failed run. Zero rows because the SEC did not answer — 403, 5xx, timeouts, or a maintenance page instead of JSON — finishes SUCCEEDED with zero results, and the status message names the cause, including which of the SEC's two 403s it was, rate-limited or user-agent-rejected; nothing is charged, start fee included. Zero rows because the answer was empty — a ticker that does not exist, a CIK with no submissions record, a form filter matching no filings, a company with no XBRL facts — finishes the same way, with diagnostic rows naming each one. Those are answers, just not the ones you hoped for, and you are not charged for them — neither the diagnostic rows nor the start fee. A run finishes FAILED only when the Actor itself hit an error.

The run says rate-limited. What now? The SEC throttles by requester, not by machine, and states that access is limited for about ten minutes once its 10 req/s ceiling is crossed. This Actor holds a whole run to 8 req/s, so a rate block usually means other traffic sharing your identity or your address — including your own parallel runs. Wait a few minutes and run again, or split the work into smaller runs. Nothing is charged for the rows that could not be fetched.

Is any of this investment advice? No. This Actor reproduces public regulatory filings. It does not interpret them.

  • Not affiliated with, endorsed by, or sponsored by the U.S. Securities and Exchange Commission. "EDGAR" and "SEC" are used descriptively to identify the public data source.
  • All data comes from US federal public records that the SEC publishes explicitly for programmatic access. No login, no authentication, no paywall is bypassed.
  • The Actor honours the SEC's published access policy: a descriptive User-Agent on every request and a self-imposed limit of 8 requests per second — counted across the whole run, not per fetcher — against a published ceiling of 10.
  • Nothing here is investment, legal, or tax advice. Filing data may contain errors, omissions, or restatements; verify against the source documents, which are linked on every row.
  • Company officers' names appear in some filings as a matter of public record. This Actor does not extract, enrich, or infer personal data beyond what the SEC itself publishes in the structured fields listed above.

Our other Actors

Every Insight Solutions Actor is pay-per-result with no browser, no login and no API key, and every one of them returns free diagnostic rows instead of billing for failures. Prices are per 1,000 results.

Video, audio & social

News, documents & the web

Business, finance & jobs

Apps & games