Skip to main content

Official Python SDK for the SEC API (secapi.dev) - SEC filings, financials, insider and institutional data.

Project description

secapi - Python SDK for the SEC API

The official Python client for secapi.dev - SEC filings, financial statements, standardized metrics & ratios, insider transactions, and 13F institutional holdings, all from one clean, typed client.

from secapi import SECClient

client = SECClient(api_key="YOUR_API_KEY")

results = client.filings.search(ticker="AAPL", form="10-K")
print(results)
  • Pleasant, resource-oriented API - client.filings.search(...), client.financials.income_statement(...). No URLs to build.
  • Typed responses - real objects with autocomplete (filing.accession_number, filing.filing_date), powered by Pydantic v2. No dictionary spelunking.
  • Helpful errors - AuthenticationError, RateLimitError, NotFoundError, ValidationError, ServerError instead of raw HTTP codes.
  • Fast & robust - built on httpx with HTTP/2, connection pooling, timeouts, and automatic retries with backoff.
  • Stays in sync with the API - models are generated from the API's OpenAPI spec.

Installation

pip install secapi-py

The PyPI package is secapi-py (the plain secapi name is taken by another project). Import it as:

from secapi import SECClient

Requires Python 3.8+.

Authentication

Get an API key from secapi.dev. Provide it explicitly:

client = SECClient(api_key="YOUR_API_KEY")

...or set an environment variable and omit the argument:

export SECAPI_API_KEY="YOUR_API_KEY"
client = SECClient()  # reads SECAPI_API_KEY

Quickstart

from secapi import SECClient

client = SECClient(api_key="YOUR_API_KEY")

# Find Apple's annual reports
filings = client.filings.search(ticker="AAPL", form="10-K", limit=5)
for filing in filings.data:
    print(filing.filing_date, filing.form_type, filing.accession_number)

# Pull the latest income statement for Microsoft
income = client.financials.income_statement(ticker="MSFT")
for row in income.rows or []:
    print(row.plabel)

Resources

Every top-level API category is its own namespace on the client.

client.filings

client.filings.search(ticker="AAPL", form=["10-K", "8-K"], start_date="2025-01-01")
client.filings.get("0000320193-26-000006")               # every filing for an accession no.
client.filings.retrieve("0000320193", "0000320193-26-000006")
client.filings.documents("0000320193", "0000320193-26-000006")
client.filings.form_types()

client.financials

# As-reported statements - by accession number, or by ticker/CIK (latest filing)
client.financials.income_statement(ticker="MSFT")
client.financials.balance_sheet("0000320193-26-000006")
client.financials.cash_flow(ticker="AAPL", form="10-K")

# Standardized statements, raw XBRL, company & concept search
client.financials.income_statement_standardized(ticker="AAPL")
client.financials.xbrl("0000320193-26-000006")
client.financials.companies(ticker="AAPL")
client.financials.concepts("revenue")

# Cross-period metrics, ratios and rankings
client.financials.metrics(["revenue", "net_income"], ticker="AAPL")
client.financials.ratios(ticker="AAPL", group="profitability")
client.financials.top_metrics("revenue", limit=10)
client.financials.top_ratios("gross_margin")

# Revenue segments
client.financials.segments_geography("AAPL")
client.financials.segments_product_service("AAPL", period="2024")

client.entities

client.entities.get("AAPL")              # by ticker or CIK
client.entities.list(q="Apple", limit=20)
client.entities.filings("AAPL", form="10-K")
client.entities.sic_codes()

client.insiders

client.insiders.latest(limit=50)                       # newest insider trades
client.insiders.search(ticker="AAPL", acquired_disposed="A")
client.insiders.transactions(person_cik="0001214123")  # one insider
client.insiders.buying(limit=25)
client.insiders.top_buyers()
client.insiders.owners("AAPL")
client.insiders.buy_sell_ratio("AAPL")
client.insiders.person("0001214123")

client.institutions

client.institutions.list(q="Berkshire")
client.institutions.holdings("0001067983", sort="value")
client.institutions.buys("0001067983", quarter="2024Q3")
client.institutions.sectors("0001067983")
client.institutions.activity()                          # market-wide smart money

Typed responses

Responses are Pydantic models, so you get attribute access and editor autocomplete instead of raw dictionaries:

filings = client.filings.search(ticker="AAPL", form="10-K")

first = filings.data[0]
first.company_name      # -> entity_name on the model
first.accession_number  # "0000320193-26-000006"
first.filing_date       # datetime.date(2026, 1, 15)
filings.pagination.has_more_data  # True / False

Need a plain dict? Every model has .to_dict() (snake_case) and .to_dict(by_alias=True) (the original API keys). Unknown fields the API adds in the future are preserved automatically, so your code keeps working.

Error handling

from secapi import SECClient
from secapi.exceptions import (
    AuthenticationError,
    RateLimitError,
    NotFoundError,
    ValidationError,
    ServerError,
    SecApiError,
)

client = SECClient(api_key="...")
try:
    client.entities.get("AAPL")
except RateLimitError as exc:
    print("Slow down:", exc.message)
except AuthenticationError:
    print("Check your API key")
except NotFoundError:
    print("No such entity")
except SecApiError as exc:        # base class for everything this SDK raises
    print("Request failed:", exc)

Every APIStatusError exposes .status_code, .code, .message, .details, and .request_id (handy when contacting support).

Configuration

import httpx
from secapi import SECClient

client = SECClient(
    api_key="...",
    timeout=httpx.Timeout(30.0, connect=10.0),  # or a float
    max_retries=2,         # retries 429/5xx with exponential backoff
    http2=True,            # enabled by default
    base_url="https://api.secapi.dev",
)

# Reuse the client across requests; close it (or use a context manager) when done.
with SECClient(api_key="...") as client:
    client.filings.search(ticker="AAPL")

Internals you can reach for if you need them: client.session (the underlying httpx.Client), client.base_url, and client.api_key.

Development

The response models are generated from the API's OpenAPI document (https://api.secapi.dev/api/core/v3/api-docs), vendored at scripts/openapi.json.

pip install -e ".[dev]"

# Regenerate models from the spec
python scripts/generate_models.py

# Fail if the committed models drift from the spec (run this in CI)
python scripts/generate_models.py --check

# Unit tests (offline, mocked transport)
pytest

# Integration tests against the live API
export SECAPI_API_KEY="YOUR_API_KEY"
pytest -m integration

License

MIT - see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

secapi_py-0.1.1.tar.gz (65.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

secapi_py-0.1.1-py3-none-any.whl (43.1 kB view details)

Uploaded Python 3

File details

Details for the file secapi_py-0.1.1.tar.gz.

File metadata

  • Download URL: secapi_py-0.1.1.tar.gz
  • Upload date:
  • Size: 65.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for secapi_py-0.1.1.tar.gz
Algorithm Hash digest
SHA256 32631744cdce429cb46a6a8678805f830610423134fc8ee8311cb8bf4577fbe5
MD5 c791c08867f970d5cee24eb60713ac57
BLAKE2b-256 99089a1677ffb0fb298505f54b45d37256cb6805c6a5b77cc3db68be4da7999a

See more details on using hashes here.

Provenance

The following attestation bundles were made for secapi_py-0.1.1.tar.gz:

Publisher: release.yml on secapi-dev/secapi-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file secapi_py-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: secapi_py-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 43.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for secapi_py-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 b5fad8fcfda9b20b7c07beab90e93b4df1cf6373b95b159ed7f8550388c04758
MD5 8546725dbd7045463134131e0e85aa15
BLAKE2b-256 205817b838e16ff0b037185f0b03335dce68ec55752ff7cb48a63407591289c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for secapi_py-0.1.1-py3-none-any.whl:

Publisher: release.yml on secapi-dev/secapi-python

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page