If you have ever wanted to find every SEC filing that mentions a phrase, a person, or a legal term, EDGAR has a full text search index that covers every filing since 2001. It is a plain JSON API, no key and no login, and most people never touch it directly.
The endpoint
GET https://efts.sec.gov/LATEST/search-index?q=%22material+weakness%22&forms=10-K&startdt=2026-01-01&enddt=2026-06-30
Enter fullscreen mode Exit fullscreen mode
Parameters:
-
qis the query. Wrap a phrase in double quotes for an exact match. -
formsis an optional comma list of form types, e.g.8-K,10-K. -
startdtandenddtscope the filing date (withdateRange=custom). -
ciksrestricts to one or more companies by CIK number. -
fromis the paging offset.
EDGAR asks for a descriptive User-Agent with contact info. Send one and you are fine:
const res = await fetch(url, {
headers: {
Accept: 'application/json',
'User-Agent': 'YourApp [email protected]',
},
});
Enter fullscreen mode Exit fullscreen mode
The response shape
Results come back Elasticsearch style under hits.hits. Each hit has an _id and a _source:
{
"_id": "0001493152-26-015257:form10-ka.htm",
"_source": {
"display_names": ["Where Food Comes From, Inc. (WFCF) (CIK 0001360565)"],
"ciks": ["0001360565"],
"form": "10-K/A",
"file_date": "2026-04-06",
"adsh": "0001493152-26-015257"
}
}
Enter fullscreen mode Exit fullscreen mode
Two useful tricks:
The display_names string packs the company, ticker, and CIK together. A small regex pulls them apart:
const m = name.match(/^(.*?)\s*\(([^)]+)\)\s*\(CIK\s*\d+\)\s*$/);
const companyName = m ? m[1].trim() : name;
const ticker = m ? m[2].trim() : null;
Enter fullscreen mode Exit fullscreen mode
The _id is accession:filename, and adsh is the accession number. Combine them into a direct link to the document:
const filename = id.slice(id.indexOf(':') + 1);
const nodash = adsh.replace(/-/g, '');
const cik = String(Number(ciks[0])); // strip leading zeros
const url = `https://www.sec.gov/Archives/edgar/data/${cik}/${nodash}/${filename}`;
Enter fullscreen mode Exit fullscreen mode
Paging
Each request returns up to 100 hits. Advance from in steps of 100 until you have what you need. EDGAR caps deep paging at a 10,000 result window per query, so read the reported hits.total.value and stop there.
let from = 0;
while (from < 10000) {
const data = await getJson(buildUrl(from));
const hits = data.hits.hits;
if (hits.length === 0) break;
// ...process hits...
if (hits.length < 100) break;
from += 100;
}
Enter fullscreen mode Exit fullscreen mode
Why it is handy
Full text search across every filer is a different job from watching one company or one form. You can catch risk language like “going concern” or “material weakness” wherever it lands, follow an executive across filers, or track a product mention over time. And because it is a light JSON GET, a run costs almost nothing.
If you want this packaged instead of maintained by hand, I run it as a keyless pay per use actor on Apify. Give it a query and it returns one JSON row per filing with a direct link. The first rows of every run are free so you can check the output.
답글 남기기