Search the full body text of SEC EDGAR filings (10-K, 10-Q, 8-K, S-1, DEF 14A, 13F, 13D/G, Form 4, etc., 2001-present) via the public efts.sec.gov JSON API, with filters for form type, filer (CIK or name), filer location, SIC code, and date range. Returns structured filing metadata plus canonical filing-index and document URLs.
Automate repetitive workflows and reduce manual effort
Example: Generate reports, summarize documents, draft communications
Save 3-5 hours per week on routine tasks
Learn new skills, understand complex topics, get expert guidance
Example: Explain concepts, provide examples, suggest learning resources
Accelerate learning and skill development by 2x
Enhance output quality through reviews, suggestions, and refinements
Example: Review drafts, suggest improvements, catch errors
Improve work quality by 30-40% with less effort
Time estimate: 15-45 minutes depending on use case complexity
Prerequisites
Submit your Claude Code skill and start earning
browse install sec.gov/search-edgar-fulltext-dpk6r2Compatible with
Supported agents
| name | search-edgar-fulltext |
| title | SEC EDGAR Full-Text Filing Search |
| description | >- Search the full body text of SEC EDGAR filings (10-K, 10-Q, 8-K, S-1, DEF 14A, 13F, 13D/G, Form 4, etc., 2001-present) via the public efts.sec.gov JSON API, with filters for form type, filer (CIK or name), filer location, SIC code, and date range. Returns structured filing metadata plus canonical filing-index and document URLs. |
| website | sec.gov |
| category | finance |
| tags | - sec - edgar - filings - full-text-search - regulatory - json-api |
| source | 'browserbase: agent-runtime 2026-05-18' |
| updated | '2026-05-18' |
| recommended_method | api |
| alternative_methods | [] |
| verified | false |
| proxies | false |
Search the full body text of every SEC EDGAR filing accepted electronically since 2001 — 10-K, 10-Q, 8-K, S-1, S-3, 424B*, DEF 14A, SC 13D, SC 13G, 13F-HR, Forms 3/4/5, N-PX, and dozens of others — for a phrase or boolean expression, and return a structured list of matching filings with filer identity, form type, filing date, period of report, business + incorporation state, SIC code, the canonical filing-index URL, and the direct URL to the matching exhibit. Read-only.
This is distinct from EDGAR's filing-metadata browse surface (/cgi-bin/browse-edgar), which lists filings by company without looking inside them. This skill searches the body text.
EDGAR's full-text search is backed by a single public JSON endpoint: https://efts.sec.gov/LATEST/search-index (an AWS API Gateway in front of an OpenSearch/Elasticsearch cluster, accept-cors *, no auth, no cookies, no captcha). The consumer SPA at https://www.sec.gov/edgar/search/ is a thin jQuery wrapper that calls this exact endpoint and renders the same metadata fields. Always use the JSON endpoint directly — the browser path costs ~50× more agent turns and returns no extra data.
GET https://efts.sec.gov/LATEST/search-index
?q=<phrase-or-boolean>
[&forms=<csv>]
[&dateRange=custom&startdt=YYYY-MM-DD&enddt=YYYY-MM-DD]
[&ciks=<csv-of-10-digit-zero-padded>]
[&entityName=<text>]
[&locationCodes=<csv-of-state-codes>]
[&locationType=located|incorporated]
[&sics=<csv-of-4-digit-codes>]
[&sort=desc|asc]
[&from=N]
Headers:
User-Agent: <YourOrg> <contact@example.com> # SEC fair-access courtesy
Accept: application/json
The q parameter accepts:
q=catastropheq=%22climate+risk%22 ("climate risk")q=%22going+concern%22+AND+NOT+%22substantial+doubt%22. Supported operators: AND, OR, NOT, parentheses. Default operator between bare terms is AND.Filter parameters and their semantics (every one verified live against the API on 2026-05-18):
| Param | Type | Meaning |
|---|---|---|
forms | csv | Form codes (10-K, 10-Q, 8-K, S-1, DEF 14A, SC 13D, SC 13G, 13F-HR, 4, 424B, N-PX, …). Matches the root form — forms=10-K returns both 10-K and 10-K/A (verified). Multi-form: forms=10-K,8-K. |
dateRange | enum | Must be custom for startdt/enddt to take effect. |
startdt / enddt | YYYY-MM-DD | Bounds on file_date (the date the filing landed at EDGAR, not the period of report). Both inclusive. |
ciks | csv | 10-digit zero-padded CIK (e.g. 0000320193 for Apple, not 320193). Multi: 0000320193,0001652044. Filters to filings where the CIK appears in _source.ciks[] — i.e. filer or co-filer or insider-subject (Form 4). |
entityName | string | Fuzzy text match on the company/individual-name index. Multi-select in the UI; comma-separate to OR them. Useful when you only know the name. The API returns CIKs in the results — cache them and switch to ciks= for repeat queries (more precise). |
locationCodes | csv | 2-letter state code (CA, NY, …) or 2-char EDGAR foreign code (e.g. X0 = England). Plural form required — the singular locationCode= is silently ignored. |
locationType | enum | located (default — matches _source.biz_states[], the filer's business-address state) or incorporated (matches _source.inc_states[], the state of incorporation). |
sics | csv | 4-digit Standard Industrial Classification codes (e.g. 2834 pharma, 6022 state commercial banks, 7372 software). Multi-select supported. |
sort | enum | desc = file_date newest first, asc = oldest first. Omit for default relevance (_score) sort. The variants sortBy=date, order=date are silently ignored — only `sort=desc |
from | int | Pagination offset. Page size is fixed at 100 when from is set. ES max_result_window caps from + size ≤ 10000 → effective ceiling from=9900. See gotcha below for deeper paging. |
The endpoint accepts any modern User-Agent; the SEC's fair-access policy requests (but does not enforce at this endpoint) a UA identifying your org plus a contact email. A bare Chrome UA returns 200 fine. Stay under 10 req/s aggregate to www.sec.gov + efts.sec.gov.
Through Browserbase's server-side Fetch API:
browse cloud fetch \
"https://efts.sec.gov/LATEST/search-index?q=%22climate+risk%22&forms=10-K&dateRange=custom&startdt=2024-01-01&enddt=2024-03-31&from=0" \
--output /tmp/edgar.json
Or any HTTP client with Accept: application/json.
{
"took": 1975,
"timed_out": false,
"_shards": { "total": 50, "successful": 50, "skipped": 0, "failed": 0 },
"hits": {
"total": { "value": 281, "relation": "eq" },
"max_score": 7.69,
"hits": [ /* one entry per filing — see below */ ]
},
"aggregations": {
"entity_filter": { "buckets": [ { "key": "...", "doc_count": 2 }, ... ] },
"sic_filter": { "buckets": [ { "key": "6022", "doc_count": 57 }, ... ] },
"biz_states_filter": { "buckets": [ { "key": "NY", "doc_count": 51 }, ... ] },
"form_filter": { "buckets": [ { "key": "10-K", "doc_count": 281 } ] }
},
"query": { /* the ES query echo (useful for debugging) */ }
}
hits.total.value is the true total. relation: "eq" means exact; "gte" appears when the bucket is capped (typically at 10,000). When you see gte, narrow your filters to get an exact count.hits.hits[] is the page of matches (length ≤ 100 per request).aggregations gives top-30 facet buckets for entity / sic / biz_states / form — useful for refining a too-wide query.Each hit:
{
"_index": "edgar_file",
"_id": "0000815097-24-000011:ccl-20231130.htm",
"_score": 7.69,
"_source": {
"adsh": "0000815097-24-000011",
"ciks": ["0000815097", "0001125259"],
"display_names": ["CARNIVAL CORP (CCL) (CIK 0000815097)", "CARNIVAL PLC (CUK, CUKPF) (CIK 0001125259)"],
"form": "10-K",
"root_forms": ["10-K"],
"file_type": "10-K",
"file_description":"10-K",
"file_date": "2024-01-26",
"period_ending": "2023-11-30",
"biz_states": ["FL", "X0"],
"inc_states": ["DE"],
"biz_locations": ["Miami, FL", "Southampton So15 1st, X0"],
"sics": ["4400", "4400"],
"file_num": ["001-09610", "001-15136"],
"film_num": ["24564723", "24564724"],
"items": [],
"sequence": 1,
"xsl": null
}
}
Field notes:
_id has the structural format {adsh}:{filename} — split on the first :. The accession number is on the left; the filename of the exhibit that matched is on the right.adsh is the accession number with hyphens. Drop them to get the directory name for the URL.ciks[] is always zero-padded 10-digit. Multi-CIK hits arise for joint filings (co-filers in a 10-K) and for Form 4/3/5 hits where the filer is the reporting officer and the second CIK is the issuer. The first CIK in the array is the primary filer for URL purposes.display_names[] is the human-readable filer label EDGAR shows in the UI (Company (TICKER) (CIK xxx)); each entry pairs 1-to-1 with ciks[].form is the exact form code (with /A amendment suffix when applicable). root_forms[] is the parent (10-K covers 10-K/A, 8-K covers 8-K/A). forms= query filter matches against root_forms[].file_date ≠ period_ending. Filing date is when EDGAR accepted the filing; period of report is the as-of date (e.g. fiscal year-end for a 10-K). For 8-Ks, period_ending is the event date.biz_states[] / inc_states[] use 2-letter US state codes plus EDGAR's foreign codes: X0=England, X1=… (one of the international codes), A0/D0=…, XX/ZZ=other. Treat any code that's not in the US 50+DC+territories list as "foreign / unknown" for downstream consumers.sics[] is the 4-digit SIC code per filer CIK. Multi-filer hits have one SIC entry per CIK.items[] is populated only for 8-Ks — the list of 8-K event item codes ("2.02", "5.02", etc.). Empty for other forms._score is the relevance score from the underlying OpenSearch query. Default sort is _score desc.EDGAR's filing archive uses a deterministic directory layout under https://www.sec.gov/Archives/edgar/data/{cik_int}/{adsh_no_dashes}/:
cik_int = int(_source.ciks[0]) # strip leading zeros: "0000815097" → 815097
adsh_no_dashes = _source.adsh.replace("-", "") # "0000815097-24-000011" → "000081509724000011"
filename = _id.split(":", 1)[1] # the part after the colon in the hit's _id
filing_index_url = f"https://www.sec.gov/Archives/edgar/data/{cik_int}/{adsh_no_dashes}/{adsh}-index.htm"
document_url = f"https://www.sec.gov/Archives/edgar/data/{cik_int}/{adsh_no_dashes}/{filename}"
Both URLs verified live (HTTP 200) against https://www.sec.gov/Archives/edgar/data/815097/000081509724000011/0000815097-24-000011-index.htm and .../ccl-20231130.htm.
The filing-index page is small (~20 KB) and lists every exhibit in the filing. The direct document URL is the exact .htm or .txt that contained the matching phrase — typically the primary exhibit (the 10-K body, not Exhibit 21 subsidiaries unless that's where the term appeared).
If you need the filer's full filing history (not just this one hit), use the metadata-browse URL — that's a separate skill, but for completeness: https://www.sec.gov/cgi-bin/browse-edgar?action=getcompany&CIK={cik_int}&type={form_code}&dateb=&owner=include&count=40.
Append &from=100, &from=200, … to walk pages of 100 hits. Stop when you've collected hits.total.value results, or when len(hits.hits) < 100 (last page).
For result sets larger than 10,000:
from + size > 10000 (verified: returns 200 with errorType: ResponseError, errorMessage: "search_phase_execution_exception: ... Result window is too large, from + size must be less than or equal to: [10000]").dateRange (or forms / locationCodes / sics) and walk the narrower buckets sequentially. With sort=asc + a tight date window per page, you can sweep an unbounded corpus.For each hits.hits[i], surface:
{
"accession_number": "_source.adsh",
"filer_cik": "_source.ciks[0]",
"filer_name": "_source.display_names[0]",
"co_filer_ciks": "_source.ciks[1:]",
"co_filer_names": "_source.display_names[1:]",
"form": "_source.form",
"root_form": "_source.root_forms[0]",
"file_date": "_source.file_date",
"period_ending": "_source.period_ending",
"items_8k": "_source.items",
"filer_biz_state": "_source.biz_states[0]",
"filer_inc_state": "_source.inc_states[0]",
"filer_sic": "_source.sics[0]",
"filer_biz_location": "_source.biz_locations[0]",
"matched_file": "_id.split(':', 1)[1]",
"score": "_score",
"filing_index_url": "(derived per §4)",
"document_url": "(derived per §4)"
}
Plus, at the result-set level: total_results: hits.total.value, total_is_capped: hits.total.relation != 'eq', and (optionally, when the caller wants to refine) the four aggregations.* buckets verbatim.
If the JSON endpoint is unreachable but www.sec.gov is:
https://www.sec.gov/edgar/search/#/q=<URL-encoded-query>&forms=<csv>&dateRange=custom&startdt=...&enddt=... — the SPA is hash-routed (uses hasher.min.js); query parameters live after the #/, not after ?. The page loads with the form pre-populated and auto-submits..divResultsContainer .result-section to render (the SPA injects results via jQuery after the same efts.sec.gov AJAX call you'd otherwise make directly)..result-section contains a <td class="filetype">{form}</td>, <td class="filed">{file_date}</td>, anchor <a class="preview-file" data-adsh="{adsh}" data-file-name="{filename}" href="...">, and a CIK column. Read data-adsh and data-file-name from the anchor and reconstruct the URLs per §4.Next link in the SPA — clicking it triggers another AJAX call with from=. Same 10,000-cap applies; same Akamai protection applies to www.sec.gov (the SPA wrapper page itself), so a Verified + residential-proxy session is recommended for the SPA path. The efts.sec.gov API host has no Akamai/Cloudflare in front of it — a bare BB cloud-fetch from any IP returns 200 reliably.The browser fallback offers no additional data versus the API — the SPA renders the exact same metadata fields the JSON returns. Use it only as a last resort.
CIKs must be 10-digit zero-padded. ciks=320193 returns HTTP 500 {"message":"Internal server error"}; ciks=0000320193 works. Always str(cik).zfill(10) before sending. Multi-CIK: ciks=0000320193,0001652044.
locationCodes is plural — singular locationCode is silently ignored. Confirmed: locationCode=CA returned the unfiltered 281 hits for the climate-risk Q1 2024 query; locationCodes=CA returned 31 hits all with biz_states={"CA"}. The consumer SPA's internal locationCode is rewritten to locationCodes before sending (verified in https://www.sec.gov/edgar/search/js/edgar_full_text_search.js ~line 290: if(searchParams.locationCode && searchParams.locationCode!='all') searchParams.locationCodes = searchParams.locationCode;).
locationType defaults to located (business state), not incorporated. A naive locationCodes=DE query returns 2 hits (filings where the filer's office is in Delaware, very rare); add locationType=incorporated to switch to the much more populous inc_states (Delaware-incorporated entities — 111 hits on the same query). When locationType=incorporated is set, the result set's inc_states distribution often includes Maryland (MD) too — likely from REITs and entities cross-tagged via subsidiary CIKs; treat the filter as "all hits where at least one CIK has inc_states containing your code", not strict equality.
forms=10-K matches 10-K/A too (and 8-K matches 8-K/A). The filter is on root_forms. If you specifically need to exclude amendments, post-filter on _source.form for an exact match.
No in-document snippets are returned. Despite the match_phrase query on a hidden doc_text field, the response does not include ES highlight blocks (verified: tried highlight=true, hl=on, snippet=true — none take effect; the underlying query has _source.exclude: ["doc_text"] and no highlight clause). The consumer SPA itself does not display snippets — it shows filing metadata and a link out. If the caller asks for "the exact text that matched", you must fetch the document URL separately and grep client-side for the query phrase. Note that 10-K bodies routinely run several MB and exceed Browserbase's 1 MB cloud fetch cap — use a streaming HTTP client or open the document in a session for the text extraction step.
hits.total.relation: "gte" means the count is capped at 10,000. When you see this, your query is broader than 10k. Narrow with dateRange / forms / locationCodes / sics to get an exact count.
Deep pagination is bounded at from + size ≤ 10,000. With the fixed 100-per-page size, that's max from=9900. Beyond that, the API returns a 200 envelope with an OpenSearch error JSON: search_phase_execution_exception: [illegal_argument_exception] Reason: Result window is too large, from + size must be less than or equal to: [10000] but was [10090]. There is no search_after or scroll API exposed. Workaround: narrow with a filter (most commonly a tighter dateRange), and sweep using sort=asc to walk forward in time inside each window.
sort=desc|asc only — other variants are silently ignored. sortBy=date, order=date, etc. all fall back to default relevance sort without an error. Verify your sort is taking effect by inspecting the first 2-3 file_date values in the result.
q= is required-ish — empty q=&ciks=... works (browses filings for a CIK), but the endpoint expects either q or some other selector. q= with no other filters returns relevance-sorted results across the full 10,000+ corpus.
Boolean operators must be uppercase. AND, OR, NOT. Lowercase variants are treated as plain tokens. Parentheses are supported: q=(foo+OR+bar)+AND+%22exact+phrase%22.
entityName is fuzzy and multi-match. entityName=Apple returns 88 hits across ~10 distinct "Apple"-named entities (Apple Inc., Apple Hospitality REIT, Apple Green Holding, …). For precision, resolve to a specific CIK once and use ciks= thereafter.
sics= filtering is exact on 4-digit codes. Comma-separated multi works (sics=2834,2835,2836 for biotech-adjacent). The result set's hits will only contain those SICs in _source.sics[] — verified.
X0 and other 2-char codes in biz_states[] / inc_states[] are EDGAR's foreign country codes, not US states. X0 is England, D0 is West Germany (legacy), A0 is Alberta, etc. The full table is on EDGAR's company-search help page; treat unknown codes as "international" rather than a state.
Transient 5xx (~36-byte error JSON) under load. Observed once during iter-1: a sics=2834 request returned a 36-byte {"message":"Internal server error"} body, then succeeded immediately on retry with the identical URL. Implement a retry-with-backoff of 2-3 attempts before propagating the error.
The API has CORS open (Access-Control-Allow-Origin: *) and no auth. A browser-extension or any cross-origin web client can call it directly.
No Akamai/Cloudflare on efts.sec.gov; Akamai IS present on www.sec.gov. A bare HTTP client gets efts.sec.gov JSON reliably. The consumer SPA host (www.sec.gov/edgar/search/) injects an Akamai detection script (/akam/13/{id} + bazadebezolkohpepadr variable) — under aggressive scraping this can challenge. The download URLs under www.sec.gov/Archives/edgar/data/... are not Akamai-protected and stream fine.
SEC fair-access policy: 10 req/s aggregate across all sec.gov subdomains. Stay under it. Identifying User-Agent: <YourOrg> <contact-email> is requested by policy but not enforced at the efts.sec.gov endpoint (a default Chrome UA returns 200).
_id filename can collide across different accessions in rare cases. Always carry the full _id (with the {adsh}: prefix) or the adsh field through downstream pipelines — never the filename alone — since two filings can have the same exhibit filename.
Index coverage starts 2001-05-04. A query with sort=asc and no date filter for "climate risk" on 10-Ks returned 2001-05-04 as the earliest hit, matching the SEC's published "full-text search since 2001" coverage statement. Older filings exist in EDGAR but are not in this index.
A search returning at least one hit:
{
"query": "\"climate risk\"",
"forms": ["10-K"],
"date_range": { "start": "2024-01-01", "end": "2024-03-31" },
"sort": "relevance",
"total_results": 281,
"total_is_capped": false,
"returned": 100,
"from": 0,
"next_from": 100,
"filings": [
{
"accession_number": "0000815097-24-000011",
"filer_cik": "0000815097",
"filer_name": "CARNIVAL CORP (CCL) (CIK 0000815097)",
"co_filer_ciks": ["0001125259"],
"co_filer_names": ["CARNIVAL PLC (CUK, CUKPF) (CIK 0001125259)"],
"form": "10-K",
"root_form": "10-K",
"file_date": "2024-01-26",
"period_ending": "2023-11-30",
"items_8k": [],
"filer_biz_state": "FL",
"filer_inc_state": "DE",
"filer_sic": "4400",
"filer_biz_location": "Miami, FL",
"matched_file": "ccl-20231130.htm",
"score": 7.69,
"filing_index_url": "https://www.sec.gov/Archives/edgar/data/815097/000081509724000011/0000815097-24-000011-index.htm",
"document_url": "https://www.sec.gov/Archives/edgar/data/815097/000081509724000011/ccl-20231130.htm",
"matched_snippet": null
}
],
"aggregations": {
"top_filers": [{ "name": "Carlyle Group Inc. (CG, CGABL) (CIK 0001527166)", "count": 2 }],
"top_sics": [{ "code": "6022", "count": 57 }, { "code": "6021", "count": 41 }],
"top_states": [{ "code": "NY", "count": 51 }, { "code": "CA", "count": 31 }],
"top_forms": [{ "code": "10-K", "count": 281 }]
}
}
A search returning zero hits:
{
"query": "\"material weakness\"",
"forms": ["8-K"],
"ciks": ["0000320193"],
"total_results": 0,
"total_is_capped": false,
"returned": 0,
"filings": []
}
A search where the total count is capped (broaden the alternation, narrow with filters):
{
"query": "the",
"forms": ["10-K", "8-K"],
"total_results": 10000,
"total_is_capped": true,
"returned": 100,
"from": 0,
"next_from": 100,
"filings": [ /* first 100 hits */ ],
"note": "Result set exceeds 10,000. Narrow with dateRange / locationCodes / sics and re-query to get an exact count."
}
A search where the requested page is past the ES window:
{
"query": "the",
"from": 10000,
"error": "result_window_exceeded",
"message": "from + size must be less than or equal to 10000. Narrow filters and re-paginate within the narrower set."
}
A search where the CIK was passed un-padded (the input must be fixed before retrying):
{
"error": "invalid_cik",
"message": "ciks must be 10-digit zero-padded; pad with leading zeros and retry. Received: '320193' → should be '0000320193'."
}
AI-first code editor with Composer
Before installing skills in Cursor, ensure your development environment meets these requirements:
node --versionsearch-edgar-fulltextExecute the skills CLI command in your project's root directory to begin installation:
browse install sec.gov/search-edgar-fulltext-dpk6r2Fetches search-edgar-fulltext from sec.gov/search-edgar-fulltext-dpk6r2 and configures it for Cursor.
The CLI shows a list of agents. Use arrow keys and space to select Cursor:
Confirm successful installation by checking the skill directory location:
.cursor/skills/search-edgar-fulltext
Restart Cursor to activate search-edgar-fulltext. Access via /search-edgar-fulltextin your agent's command palette.
Learn more:View source on GitHubSkills CLI docsAbout CursorWhat are agent skills?
Steps
Common Pitfalls
✓ Do
✗ Don't
💡 Pro Tips
✓ Use when
Use when skill capabilities match your task, clear ROI on time saved, and you can validate outputs. Best for repetitive tasks, learning, and quality improvement.
✗ Avoid when
Avoid when task requires deep expertise you can't validate, involves sensitive decisions, or when learning process is more valuable than speed of completion.
regulatory-affairs-head
davila7/claude-code-templates · AI/ML · tag: regulatory
track-live-scores
livescore.com/track-live-scores-txxdp5 · sports · tag: json-api
find-funding
bja.ojp.gov/find-funding-crrr3b · government-grants · tag: json-api
clinical-reports
K-Dense Inc./clinical-reports · research · tag: regulatory
find-company-filings
opencorporates.com/find-company-filings-e9ewrz · corporate-data · tag: filings
arboreto
K-Dense Inc./arboreto · data · tag: regulatory
I recommend search-edgar-fulltext for anyone iterating fast on agent tooling; clear intent and a small, reviewable surface area.
Useful defaults in search-edgar-fulltext — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
search-edgar-fulltext is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
search-edgar-fulltext has been reliable in day-to-day use. Documentation quality is above average for community skills.
search-edgar-fulltext has been reliable in day-to-day use. Documentation quality is above average for community skills.
Useful defaults in search-edgar-fulltext — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
I recommend search-edgar-fulltext for anyone iterating fast on agent tooling; clear intent and a small, reviewable surface area.
search-edgar-fulltext reduced setup friction for our internal harness; good balance of opinion and flexibility.
Keeps context tight: search-edgar-fulltext is the kind of skill you can hand to a new teammate without a long onboarding doc.
search-edgar-fulltext is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
showing 1-10 of 28