Search and list filings
Search and list SEC filings from Signal8's archive (EDGAR filings in the archive's held range — see archiveFrom in each response; currently from late 2021, expanding back to 2016 as the history backfill fills in. Older filings may be absent, so an empty result is not proof of absence). Filter by CIK, form type, date range, 8-K item codes and excluded forms; optionally full-text q (websearch syntax: unquoted words must ALL appear, "quoted phrase", OR, -exclude).
Company filters (minMarketCap … recentIpo) use the same contract as signal8.ai/sec-filings and are served from the archive only: issuer-filed forms only (Form 4 / 144 / SCHEDULE 13D/G are dropped and listed in companyFilter.droppedForms — unless companyFilter.subjectMatch is true, when they are searched by the company they are about; with no formTypes the default is 10-K, 10-Q, 8-K, S-1, S-3, DEF 14A, 20-F, 40-F, 6-K); companies with no measured value for a filter are EXCLUDED and counted in companyFilter.unknown; unknown values are a 400 that lists the valid names; an archive that cannot answer returns 503/422 COMPANY_FILTER_NOT_APPLIED with a reason — never unfiltered rows. Company-filtered requests are cursor-paged (page > 1 is a 400) and cannot be combined with aiAnalysed, hasRofr, extractionTypes, bodyStored, acceptedFrom or acceptedTo.
Credit cost: 5
Request
- Base URL: https://api.signal8.ai/api/v1/public
- URL: https://api.signal8.ai/api/v1/public/edgar/filings
- Auth: API key in header X-Api-Key
Query parameters
Comma-separated CIK numbers (e.g. "0000320193,0001018724").
Page number, 1-indexed (default: 1).
Results per page (default: 25, max: 100).
Comma-separated form types (e.g. "10-K,10-Q,8-K,S-1").
Start date filter (YYYY-MM-DD).
End date filter (YYYY-MM-DD).
Restrict to filings that have been analysed.
Restrict to filings flagged with a right-of-first-refusal clause.
Comma-separated extraction types to filter by.
Full-text query over filing bodies. Syntax: unquoted words must ALL appear; "quoted phrase" = exact wording; OR between alternatives; -word / -"phrase" to exclude; w1 NEAR/10 w2 (also NEAR(10), bare NEAR = 10) = words close together; word* = prefix of 4+ letters; $AAPL or a capitalised ticker scopes to that company; a form code (8-K), item 5.02 / 8-K 1.05 and a bare year (2024) scope to that form / 8-K item / year. The archive's reading of the query is reported in meta.understanding (disable with understand=false). Ranked when sort=relevance. Rows then carry rank and snippet.
newest (acceptance time, default) or relevance (requires q; best match first). Any other value is a 400.
Word matching for q. exact = a word matches only itself ("split" does NOT match "splits" — EDGAR full-text search's behaviour); stemmed = English word variations also match. Omitted ⇒ stemmed (the archive default). The mode actually applied is reported in meta.matchMode. Ignored without q; any other value is a 400.
true = also return top-level facets: { forms, years, items }, each [{ value, count }] over the WHOLE result set. Present only when MEASURED (the archive's OpenSearch engine); absent means not measured, never zero. Any other value is a 400.
Query understanding (default on): tickers / $TICKER, company names, form codes, item N.NN and synonym expansion, reported in meta.understanding. false = search the words literally. Ignored without q; any other value is a 400.
Auto-correction (default on): when page 1 of a text search finds (almost) nothing and its spelling correction finds materially more, the CORRECTED query is answered and meta.correction { from, to, originalTotal } says so (page on with q = correction.to — nextCursor belongs to it). false = always search q literally. meta.suggestion { text } carries a "did you mean" that was not applied. Ignored without q.
Restrict MATCHING to sections (comma-separated; needs q): business, risk_factors, cybersecurity, legal_proceedings, mdna, market_risk, controls (10-K / 10-Q / 20-F narrative items, by meaning), ex99 (press-release / EX-99.x exhibit text), item_X_YY (the text under an 8-K item, e.g. item_5_02). Aliases: mda, risk, legal, cyber, press_release, 5.02. An unknown name is a 400. Applied only when meta.sections names it; otherwise meta.unsupported carries { param: section, reason } (mapping_v1, postgres, substring, not-reported) and matches may come from anywhere in the filing.
Keep filings carrying ANY of these exhibit types (comma-separated). A family (EX-10 = material contracts) matches every member; an exact type (EX-99.1) only itself; 10.1 is accepted for EX-10.1. Others: EX-97 clawback policy, EX-3 charter / bylaws, EX-4 instruments / warrants, EX-21 subsidiaries, EX-23 consents. Invalid ⇒ 400. Listed in appliedFilters only when the returned rows prove it; otherwise in ignoredFilters and meta.unsupported (not-verified) — treat the rows as unfiltered then.
Per-row matchedSections (the sections the text matched in). Absent on a row ⇒ not measured (an index without sections), never "matched nowhere".
Opaque keyset cursor from a previous response's pagination.nextCursor. Use instead of page for deep, stable paging.
Comma-separated 8-K item codes, ALL required (e.g. "2.02,9.01").
Comma-separated form types to exclude (exact match; list amendments such as N-PX/A explicitly).
true = only filings whose body is held; false = metadata-only rows.
Acceptance-time lower bound (ISO-8601). Rows without an acceptance time compare on filing date.
Acceptance-time upper bound (ISO-8601).
Company filter. Minimum market cap in USD (price × shares outstanding).
Company filter. Maximum market cap in USD.
Company filter. Minimum public float (shares).
Company filter. Maximum public float (shares).
Company filter. Minimum latest share price (USD).
Company filter. Maximum latest share price (USD).
Company filter. Sector names separated by | (a bare comma with no following space also separates). Exact and case-sensitive. An unknown name is a 400 whose allowed lists the valid ones.
Company filter. Industry names separated by | — several names contain ", " (e.g. "Airlines, Airports & Air Services"); a bare comma with no following space also separates. Exact and case-sensitive. An unknown name is a 400 whose allowed lists the valid ones.
Company filter. Comma-separated: NASDAQ, NYSE, AMEX (NYSE American), OTC.
Company filter. Comma-separated: operating, fund, spac.
Company filter. true = foreign-issuer evidence (20-F / 40-F / 6-K seen, or ADR); false = none seen since companyFilter.foreignEvidenceSince.
Company filter. First listed within 365 days with no evidence of earlier public status.
Response
Paginated list of filings. data is the row array; pagination carries total, totalRelation ('gte' when the exact count was cut at 10,000), totalEstimate ("about N" beside a 'gte' total, absent when not estimated), hasMore and nextCursor. Rows include id (the filingId), acceptedAt (null on archive-backfilled rows), primaryDocument, bodyStored, filerCiks, itemNumbers, and — with q, unfiltered only — rank and snippet {text, matchStart, matchLength, matchCount}. source is archive; appliedFilters names the optional filters applied. On an empty first page of a text search, searchIndex is passed through: only searchIndex.complete: true makes the zero definitive, otherwise notes says so.
Every response carries archiveFrom (YYYY-MM-DD — the archive holds only a scatter of filings before it) and rangeStartsBeforeArchive. A range with no dateFrom (and no acceptedFrom), or one starting before archiveFrom, is NEVER definitive: searchIndex is complete: false with reason: "outside_held_range" and heldFrom, and notes says absence before archiveFrom is not evidence a filing was never filed — check SEC EDGAR for earlier periods.
With q, meta (when the archive states it) reports engine (postgres | opensearch), matchMode — the word matching APPLIED, which can be stemmed although exact was requested — and matchModeFallbackReason when the two differ. meta is absent when not stated; absence is not a claim about either.
meta.understanding (with q, when stated) describes how the archive read the query: tickers, companies [{cik, name}], forms, items, years, synonyms [{term, expandedTo}], proximity, wildcard, strippedQuery — each key present only when it applies. With facets=true, top-level facets { forms, years, items } (each [{value, count}]) counts the whole result set; absent when not measured. Rows may carry items (8-K item codes), exhibitTypes and primaryDocType when the archive states them.
Wave 3 (section search): with section, meta.sections is the restriction APPLIED; meta.unsupported [{param, reason}] lists params that were NOT applied (section on an index without sections, exhibitTypes the rows could not prove) — a note in notes says so too. Text rows may carry matchedSections (absent ⇒ not measured). With facets=true, facets.sections / facets.exhibitTypes appear when measured.
With sort=relevance, page 1 shows at most maxPerCompany filings per company; meta.diversity { maxPerCompany, hidden: [{cik, count}] } names the companies with more. Page on with nextCursor (page-number paging is not diversified).
Company-filtered responses add ticker to each row (no snippet), companyFilter { matchedCompanies, searchedCompanies, unknown, foreignEvidenceSince, forms, formsDefaulted, droppedForms, issuerFiledFormsOnly }, archiveFrom, and notes.
Changes
No recorded changes to this operation across all 1 revision of this API.