SEC EDGAR API Guide: Complete Free Developer Reference
The SEC EDGAR API is one of the most valuable free data sources for financial developers. This guide covers every endpoint, rate limit, authentication requirement, and best practice, with complete Python and JavaScript code examples to get you up and running immediately.
Does SEC EDGAR Have a Free API?
Yes. The U.S. Securities and Exchange Commission provides a completely free, publicly accessible REST API for programmatic access to EDGAR financial data. The API is hosted at https://data.sec.gov and requires no registration, API key, OAuth token, or payment of any kind. The SEC launched the current structured data API in 2021 as part of its initiative to democratize access to financial disclosure data.
The SEC's free API is not a limited preview or rate-restricted public tier of a paid service โ it is the complete, production-grade API used by financial professionals, academic researchers, and independent developers to access the same data that powers SEC EDGAR's own web interface. Commercial financial data platforms (Bloomberg, FactSet, Refinitiv) use the same EDGAR data as their primary source for U.S. public company filings.
The free API covers virtually all EDGAR data including: the complete filing history for every company (over 35 million filings), XBRL-tagged financial data extracted from 10-K and 10-Q filings, company metadata (CIK, SIC code, state of incorporation, fiscal year end), full-text search across all filing content, and the company_tickers.json mapping file linking tickers to CIKs. The only data not available via structured API is pre-XBRL financial data (pre-2009 for most companies), which must be parsed from the original HTML or text documents.
API Base URLs and Endpoints Overview
The EDGAR API operates across several base URLs:
https://data.sec.govโ Primary API for submissions, financial facts, company facts, and company concept datahttps://efts.sec.govโ EDGAR Full-Text Search System (EFTS) for content-based filing searchhttps://www.sec.gov/files/โ Supplementary data files including company_tickers.jsonhttps://www.sec.gov/Archives/edgar/data/โ Direct access to filing documents by CIK and accession number
The four primary API endpoints are:
- Company Submissions:
data.sec.gov/submissions/CIK{cik10}.jsonโ complete filing history and company metadata - Company Facts:
data.sec.gov/api/xbrl/companyfacts/CIK{cik10}.jsonโ all XBRL financial data - Company Concept:
data.sec.gov/api/xbrl/companyconcept/CIK{cik10}/{taxonomy}/{concept}.jsonโ single financial concept over time - Frames:
data.sec.gov/api/xbrl/frames/{taxonomy}/{concept}/{units}/CY{year}{period}.jsonโ cross-company data for a single concept
Authentication: User-Agent Header Requirement
The EDGAR API does not require an API key or OAuth authentication. However, the SEC explicitly requires all programmatic users to include a descriptive User-Agent header in every request. This is a condition of using the API, not an optional courtesy.
The required format is: User-Agent: ApplicationName/Version ([email protected])
Examples of valid User-Agent headers:
MyStockScreener/2.0 ([email protected])FinancialResearchApp/1.0 ([email protected])PersonalProject/0.1 ([email protected])
The SEC uses the User-Agent to identify applications causing unusual traffic patterns and to contact developers if their usage causes problems. Requests without a proper User-Agent header may be blocked, particularly during high-traffic periods. In Python's requests library: headers = {"User-Agent": "MyApp/1.0 ([email protected])"}. In JavaScript fetch: headers: { "User-Agent": "MyApp/1.0 ([email protected])" }.
CIK Number Formatting
CIK numbers must be zero-padded to exactly 10 digits in all API URLs. This is a non-obvious but critical requirement โ requests with improperly formatted CIKs return 404 errors that can be confusing to debug.
The zero-padding rule: take the raw CIK (which may be 1-10 digits) and left-pad it with zeros to reach exactly 10 digits. In Python: cik_padded = str(cik).zfill(10). In JavaScript: String(cik).padStart(10, "0").
Examples:
- Apple Inc. CIK: 320193 โ
0000320193โ URL:data.sec.gov/submissions/CIK0000320193.json - Microsoft CIK: 789019 โ
0000789019โ URL:data.sec.gov/submissions/CIK0000789019.json - Tesla CIK: 1318605 โ
0001318605โ URL:data.sec.gov/submissions/CIK0001318605.json
The company_tickers.json file provides CIK values as raw strings without zero-padding (e.g., "320193"). Your application must add the zero-padding when constructing API URLs. Use our CIK Lookup tool to find and verify any company's CIK.
Company Submissions Endpoint
The submissions endpoint retrieves the complete filing history and metadata for any EDGAR registrant.
URL pattern: https://data.sec.gov/submissions/CIK{cik10}.json
The JSON response structure:
{
"cik": "320193",
"name": "Apple Inc.",
"sic": "3571",
"sicDescription": "Electronic Computers",
"stateOfIncorporation": "CA",
"fiscalYearEnd": "0928", // MMDD format
"filings": {
"recent": {
"accessionNumber": ["0000320193-24-000123", ...],
"filingDate": ["2024-02-02", ...],
"form": ["10-K", ...],
"primaryDocument": ["0000320193-24-000123.htm", ...],
"primaryDocDescription": ["10-K", ...],
"items": ["", ...] // 8-K items for current event reports
// ... plus 10+ more parallel arrays
},
"files": [ // For companies with 1000+ filings
{"name": "CIK0000320193-submissions-001.json", "filingCount": 1000}
]
}
}
The filings.recent object uses a "column-oriented" format: parallel arrays where index 0 in each array corresponds to the same filing. This is more space-efficient than an array of objects. To reconstruct a filing record: zip the corresponding elements from accessionNumber, filingDate, form, and primaryDocument arrays at the same index.
Company Facts Endpoint (XBRL Financial Data)
The company facts endpoint provides all XBRL-tagged financial data for a company across all periods and form types where XBRL was submitted.
URL pattern: https://data.sec.gov/api/xbrl/companyfacts/CIK{cik10}.json
The response contains a nested structure organized by taxonomy (us-gaap, dei, ifrs-full) and then by individual concept name. Each concept contains arrays of historical values. For example, to get all reported values of total assets:
// Navigate to: facts.us-gaap.Assets.units.USD
// Each entry in the array:
{
"end": "2023-09-30", // period end date
"val": 352583000000, // value in USD (no scaling)
"accn": "0000320193-23-000106", // accession number
"fy": 2023, // fiscal year
"fp": "FY", // fiscal period (FY, Q1, Q2, Q3)
"form": "10-K", // form type
"filed": "2023-11-03", // date filed
"frame": "CY2023Q3I" // XBRL frame identifier
}
XBRL coverage begins approximately 2009 for large accelerated filers. For most S&P 500 companies, you will find 15+ years of quarterly and annual financial data accessible through this endpoint. The company facts response for a large company can be 5-20MB, so cache it server-side rather than fetching on every request.
Rate Limiting and Best Practices
The SEC's informal rate limit guidance is to stay below 10 requests per second from a single IP address. In practice, a well-designed application making sequential requests with short delays will rarely approach this limit during normal operation. The most important rule is: do not make many concurrent requests in parallel.
Best practices for EDGAR API usage:
- Mandatory User-Agent header on every request. Use your real contact email โ the SEC may need to reach you if your usage pattern causes issues.
- Cache aggressively. Historical submission data rarely changes. Company facts endpoints for completed quarters are stable. Cache company_tickers.json for at least 24 hours โ it's 8MB and updated only once daily.
- Implement exponential backoff. If you receive a 429 (Too Many Requests) or 503, wait before retrying. Start with a 5-second wait, doubling with each subsequent failure: 5s, 10s, 20s, 40s.
- Use bulk downloads for large datasets. For data on thousands of companies, the EDGAR Financial Data Sets are more efficient than API calls.
- Handle the 1,000-filing pagination. The submissions endpoint returns the most recent 1,000 filings in
filings.recent. For companies with more than 1,000 historical filings (common for large companies), checkfilings.filesfor additional paginated files.
Python Code Example: Fetch Company Filings
Complete Python example requiring only standard library modules:
import urllib.request, json, time
USER_AGENT = "MyApp/1.0 ([email protected])"
def pad_cik(cik: int | str) -> str:
return str(cik).zfill(10)
def edgar_get(url: str) -> dict:
req = urllib.request.Request(url)
req.add_header("User-Agent", USER_AGENT)
req.add_header("Accept", "application/json")
with urllib.request.urlopen(req, timeout=30) as r:
return json.loads(r.read().decode())
def get_filings(cik, form_type=None, max_results=20):
"""Fetch recent filings for a company, optionally filtered by form type."""
data = edgar_get(
f"https://data.sec.gov/submissions/CIK{pad_cik(cik)}.json"
)
recent = data["filings"]["recent"]
filings = []
for i in range(len(recent["accessionNumber"])):
if form_type and recent["form"][i] != form_type:
continue
filings.append({
"date": recent["filingDate"][i],
"form": recent["form"][i],
"accession": recent["accessionNumber"][i],
"document": recent["primaryDocument"][i],
})
if len(filings) >= max_results:
break
return {"company": data["name"], "cik": data["cik"], "filings": filings}
def get_financial_concept(cik, concept="Assets", taxonomy="us-gaap"):
"""Get time-series values for a single financial concept."""
url = (f"https://data.sec.gov/api/xbrl/companyconcept/"
f"CIK{pad_cik(cik)}/{taxonomy}/{concept}.json")
data = edgar_get(url)
units = list(data["units"].keys())[0] # Usually "USD" or "shares"
return data["units"][units]
# Example usage
apple = get_filings(320193, form_type="10-K", max_results=5)
print(f"Company: {apple['company']} (CIK: {apple['cik']})")
for f in apple["filings"]:
url = (f"https://www.sec.gov/Archives/edgar/data/320193/"
f"{f['accession'].replace('-','')}/{f['document']}")
print(f" {f['date']} - {f['form']} - {url}")
JavaScript/TypeScript Code Example
Complete JavaScript example with ticker-to-CIK resolution and filing retrieval:
const USER_AGENT = "MyApp/1.0 ([email protected])";
// Cache company tickers to avoid repeated 8MB downloads
let _tickers = null;
async function fetchJSON(url) {
const response = await fetch(url, {
headers: { "User-Agent": USER_AGENT, "Accept": "application/json" }
});
if (!response.ok) throw new Error("EDGAR API error " + response.status + ": " + url);
return response.json();
}
async function getTickers() {
if (_tickers) return _tickers;
const data = await fetchJSON(
"https://www.sec.gov/files/company_tickers.json"
);
_tickers = Object.values(data);
return _tickers;
}
export async function searchCompanies(query) {
const tickers = await getTickers();
const q = query.toLowerCase().trim();
return tickers.filter(c =>
c.title.toLowerCase().includes(q) ||
(c.ticker && c.ticker.toLowerCase() === q)
).slice(0, 20);
}
export async function getCompanyFilings(cik, formType) {
const cik10 = String(cik).padStart(10, "0");
const url = "https://data.sec.gov/submissions/CIK" + cik10 + ".json";
const data = await fetchJSON(url);
const r = data.filings.recent;
const filings = r.accessionNumber
.map((acc, i) => ({
accession: acc,
date: r.filingDate[i],
form: r.form[i],
primaryDoc: r.primaryDocument[i]
}))
.filter(f => !formType || f.form === formType);
return { name: data.name, cik: data.cik, sic: data.sic, filings };
}
Full-Text Search API (EFTS)
The EDGAR Full-Text Search endpoint searches the content of all filings. This endpoint is what powers our Full-Text Search tool.
URL: https://efts.sec.gov/LATEST/search-index?q={query}&dateRange=custom&startdt={YYYY-MM-DD}&enddt={YYYY-MM-DD}&forms={formType}&from={offset}&size={count}
Key parameters:
q: URL-encoded search terms. Use double quotes for phrases:q=%22going+concern%22forms: Comma-separated form types:forms=10-K,10-QdateRange=custom: Required to enable date filteringsize: Results per page (max 100)from: Offset for pagination
Response: JSON with hits.hits array, each containing _source with: entity_name, file_date, form_type, accession_no, and period_of_report. The highlight field contains the text excerpt with the query term in context.
Common API Errors and Solutions
404 Not Found on a submissions URL almost always means the CIK is not zero-padded to 10 digits. Verify: data.sec.gov/submissions/CIK0000320193.json not CIK320193.json.
403 Forbidden or request blocking typically means the User-Agent header is missing or not descriptive enough. Add a proper User-Agent and retry.
429 Too Many Requests means you are hitting the rate limit. Implement exponential backoff and reduce concurrent request frequency.
503 Service Unavailable means the EDGAR API is temporarily unavailable (maintenance or high load). Wait and retry with backoff. Do not treat as a permanent error.
Empty filings.recent means the company has fewer than the recent threshold (1,000) filings. This is normal for recently registered companies. If you need older filings for a company with 1,000+ filings, check the filings.files array for additional paginated filing files.
Large response timeouts on company facts endpoints for large companies (Apple, Microsoft, etc.) reflect the large file size (5-20MB). Increase your HTTP client timeout to 30-60 seconds for these endpoints.
Frequently Asked Questions
Is the EDGAR API free?
Yes. The EDGAR REST API at data.sec.gov is completely free, with no registration or API key required. The only requirement is a User-Agent header identifying your application and contact email.
What is the EDGAR API rate limit?
The SEC's informal guidance is below 10 requests per second per IP. For batch downloads, implement 100-200ms delays between requests. Implement exponential backoff for 429 errors.
How do I format the CIK for API calls?
Zero-pad to 10 digits: Apple's CIK 320193 becomes 0000320193. In Python: str(cik).zfill(10). In JavaScript: String(cik).padStart(10, '0').
What financial data is available via the EDGAR API?
XBRL-tagged financial data from 10-K and 10-Q filings going back approximately 2009. Includes income statement, balance sheet, cash flow, and segment data for all major U.S. public companies.
How do I search SEC filing text via the API?
Use the EFTS endpoint: efts.sec.gov/LATEST/search-index?q={query}&forms={formType}&dateRange=custom&startdt={start}&enddt={end}
How do I convert a ticker to a CIK?
Download the company_tickers.json file from www.sec.gov/files/company_tickers.json. It maps CIK, ticker, and company name for all EDGAR registrants. Cache it (8MB) and search locally.