Table of Contents
- Introduction to SEC EDGAR API
- API Authentication & Setup
- Making Your First API Request
- Advanced Search Techniques
- Parsing Response Data
- Best Practices & Optimization
- Error Handling & Rate Limits
- Conclusion & Next Steps
Introduction to SEC EDGAR API
The SEC EDGAR API provides programmatic access to over 18 million SEC filings dating back to the 1990s. Whether you're building financial analysis tools, compliance monitoring systems, or investment research platforms, the EDGAR API offers comprehensive access to Forms 10-K, 10-Q, 8-K, proxy statements, and more.
🎯 What You'll Learn
By the end of this guide, you'll be able to:
- Authenticate with the SEC EDGAR API
- Perform basic and advanced search queries
- Parse JSON responses and extract key data
- Implement proper error handling and rate limiting
- Follow industry best practices for production use
Why Use the SEC EDGAR API?
Unlike manual SEC.gov searches, the EDGAR API enables:
- Automated Data Collection: Programmatically fetch filings as they're published
- Boolean Search Expressions: Complex queries with multiple criteria
- Structured Data Access: JSON/XML responses instead of HTML parsing
- Real-time Updates: Access new filings within seconds of publication
- Historical Analysis: Comprehensive data going back decades
API Authentication & Setup
Before making requests to the SEC EDGAR API, you'll need to set up authentication and understand the endpoint structure.
Getting Your API Key
First, sign up for a free API key at Kaleidoscope API. Free accounts include 300 API calls per month, perfect for testing and small projects.
# Test your API key
curl -X GET "https://api.kscope.io/v2/sec/search?key=YOUR_API_KEY&limit=1"
Setting Up Your Development Environment
Here's how to set up authentication in popular programming languages:
import requests
import os
# Store your API key securely
API_KEY = os.getenv('KALEIDOSCOPE_API_KEY')
BASE_URL = 'https://api.kscope.io/v2'
# Common headers for all requests
headers = {
'User-Agent': 'YourApp/1.0 (contact@yourcompany.com)',
'Accept': 'application/json'
}
💡 Security Best Practice
Never hardcode API keys in your source code. Use environment variables, configuration files, or secure key management services in production environments.
Making Your First API Request
Let's start with a simple request to search for Apple's recent SEC filings:
def search_sec_filings(ticker, limit=10):
"""Search for SEC filings by ticker symbol"""
url = f"{BASE_URL}/sec/search"
params = {
'key': API_KEY,
'ticker': ticker,
'limit': limit
}
response = requests.get(url, params=params, headers=headers)
response.raise_for_status()
return response.json()
# Example usage
apple_filings = search_sec_filings('AAPL', limit=5)
print(f"Found {len(apple_filings['data'])} Apple filings")
Understanding the Response Structure
The API returns a structured JSON response with the following format:
{
"data": [
{
"form_type": "10-K",
"company_name": "Apple Inc.",
"ticker": "AAPL",
"filing_date": "2024-11-01",
"accession_number": "0000320193-24-000123",
"period_ending": "2024-09-30",
"filing_url": "https://www.sec.gov/ix?doc=/Archives/edgar/data/..."
}
],
"count": 5,
"next_page": null
}
Advanced Search Techniques
The SEC EDGAR API supports sophisticated search capabilities including Boolean expressions, date ranges, and form type filtering.
Filtering by Form Types
Search for specific SEC form types to narrow your results:
def get_annual_reports(ticker, years=3):
"""Get annual 10-K reports for the past N years"""
url = f"{BASE_URL}/sec/search"
params = {
'key': API_KEY,
'ticker': ticker,
'form_type': '10-K',
'date_from': f'{2025 - years}-01-01',
'date_to': '2025-01-01'
}
response = requests.get(url, params=params, headers=headers)
return response.json()
Boolean Search Expressions
Use Boolean logic for complex search queries:
def search_acquisition_filings(company_name):
"""Search for merger & acquisition related filings"""
params = {
'key': API_KEY,
'query': f'{company_name} AND (merger OR acquisition OR "tender offer")',
'form_type': '8-K,SC 13D,SC TO-I',
'limit': 20
}
response = requests.get(f"{BASE_URL}/sec/search", params=params)
return response.json()
| Parameter | Description | Example |
|---|---|---|
ticker |
Stock ticker symbol | AAPL, MSFT, GOOGL |
form_type |
SEC form types (comma-separated) | 10-K,10-Q,8-K |
date_from |
Start date (YYYY-MM-DD) | 2024-01-01 |
date_to |
End date (YYYY-MM-DD) | 2024-12-31 |
query |
Boolean search expression | "revenue recognition" AND GAAP |
cik |
Central Index Key | 0000320193 |
Parsing Response Data
Once you've retrieved filing data, you'll need to extract and process the information for your application.
Extracting Key Information
def extract_filing_summary(filing_data):
"""Extract key information from filing response"""
summary = []
for filing in filing_data['data']:
filing_info = {
'company': filing.get('company_name'),
'form': filing.get('form_type'),
'date': filing.get('filing_date'),
'period': filing.get('period_ending'),
'url': filing.get('filing_url'),
'accession': filing.get('accession_number')
}
summary.append(filing_info)
return summary
# Usage example
filings = search_sec_filings('TSLA', limit=10)
summary = extract_filing_summary(filings)
for filing in summary:
print(f"{filing['company']} filed {filing['form']} on {filing['date']}")
Handling Pagination
For large result sets, implement pagination to retrieve all available data:
def get_all_filings(ticker, form_type=None):
"""Retrieve all filings for a company with pagination"""
all_filings = []
page = 1
while True:
params = {
'key': API_KEY,
'ticker': ticker,
'page': page,
'limit': 100
}
if form_type:
params['form_type'] = form_type
response = requests.get(f"{BASE_URL}/sec/search", params=params)
data = response.json()
all_filings.extend(data['data'])
# Check if there are more pages
if not data.get('next_page') or len(data['data']) < 100:
break
page += 1
return all_filings
Best Practices & Optimization
Follow these best practices to build robust, efficient applications with the SEC EDGAR API.
Rate Limiting and Performance
⚠️ Rate Limit Guidelines
Free accounts are limited to 300 requests per month. Paid plans support up to 3,600 requests per hour. Always implement proper rate limiting to avoid hitting these limits.
import time
from functools import wraps
def rate_limit(calls_per_second=1):
"""Decorator to implement rate limiting"""
def decorator(func):
last_called = [0.0]
@wraps(func)
def wrapper(*args, **kwargs):
elapsed = time.time() - last_called[0]
left_to_wait = 1 / calls_per_second - elapsed
if left_to_wait > 0:
time.sleep(left_to_wait)
result = func(*args, **kwargs)
last_called[0] = time.time()
return result
return wrapper
return decorator
# Apply rate limiting to API calls
@rate_limit(calls_per_second=0.5)
def api_request(url, params):
return requests.get(url, params=params, headers=headers)
Caching Responses
Implement caching to reduce API calls and improve performance:
import json
import hashlib
from pathlib import Path
class SECAPIClient:
def __init__(self, api_key, cache_dir='./cache'):
self.api_key = api_key
self.cache_dir = Path(cache_dir)
self.cache_dir.mkdir(exist_ok=True)
def _get_cache_key(self, params):
"""Generate cache key from request parameters"""
param_str = json.dumps(params, sort_keys=True)
return hashlib.md5(param_str.encode()).hexdigest()
def search_with_cache(self, params, cache_hours=24):
"""Search with local caching"""
cache_key = self._get_cache_key(params)
cache_file = self.cache_dir / f"{cache_key}.json"
# Check if cached version exists and is recent
if cache_file.exists():
cache_age = time.time() - cache_file.stat().st_mtime
if cache_age < cache_hours * 3600:
with open(cache_file) as f:
return json.load(f)
# Make API request and cache result
params['key'] = self.api_key
response = requests.get(f"{BASE_URL}/sec/search", params=params)
data = response.json()
# Save to cache
with open(cache_file, 'w') as f:
json.dump(data, f)
return data
Error Handling & Rate Limits
Robust error handling is essential for production applications using the SEC EDGAR API.
import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.retry import Retry
class SECAPIError(Exception):
"""Custom exception for SEC API errors"""
pass
def create_session_with_retries():
"""Create requests session with automatic retries"""
session = requests.Session()
retry_strategy = Retry(
total=3,
backoff_factor=1,
status_forcelist=[429, 500, 502, 503, 504]
)
adapter = HTTPAdapter(max_retries=retry_strategy)
session.mount("http://", adapter)
session.mount("https://", adapter)
return session
def robust_api_request(url, params):
"""Make API request with comprehensive error handling"""
session = create_session_with_retries()
try:
response = session.get(url, params=params, headers=headers, timeout=30)
if response.status_code == 401:
raise SECAPIError("Invalid API key or authentication failed")
elif response.status_code == 429:
raise SECAPIError("Rate limit exceeded. Please try again later.")
elif response.status_code >= 400:
raise SECAPIError(f"API request failed: {response.status_code} - {response.text}")
return response.json()
except requests.exceptions.RequestException as e:
raise SECAPIError(f"Network error: {str(e)}")
except json.JSONDecodeError:
raise SECAPIError("Invalid JSON response from API")
Ready to Start Building?
Get your free API key and start accessing 18M+ SEC filings today. No credit card required for the free tier.
Conclusion & Next Steps
You now have the foundation to integrate the SEC EDGAR API into your applications. This guide covered authentication, search techniques, data parsing, and production best practices.
Next Steps
- Explore Other APIs: Check out our 13F Holdings API and Insider Trading API
- Advanced Features: Learn about XBRL parsing and financial statement extraction
- Real-time Alerts: Set up webhooks for instant filing notifications
- Scale Up: Upgrade to a paid plan for higher rate limits and advanced features
Additional Resources
- Complete API Documentation
- 13F Holdings vs Insider Trading Guide
- Real-time Compliance Monitoring
- Contact Support for technical questions
Happy coding! If you build something cool with the SEC EDGAR API, we'd love to hear about it.