Skip to main content

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.

Metadata

Release files for secapi-py 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for secapi-py 0.1.1
File Size Uploaded Provenance
secapi_py-0.1.1.tar.gz 65.9 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for secapi-py 0.1.1
File Interpreter ABI Platform
secapi_py-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 108.9 kB

Release files / secapi_py-0.1.1.tar.gz

Download URL secapi_py-0.1.1.tar.gz
Size 65.9 kB
Tags Source
SHA-256 checksum
How to use checksums
32631744cdce429cb46a6a8678805f830610423134fc8ee8311cb8bf4577fbe5
BLAKE2b-256 checksum
How to use checksums
99089a1677ffb0fb298505f54b45d37256cb6805c6a5b77cc3db68be4da7999a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.

Transparency log

Release files / secapi_py-0.1.1-py3-none-any.whl

Download URL secapi_py-0.1.1-py3-none-any.whl
Size 43.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b5fad8fcfda9b20b7c07beab90e93b4df1cf6373b95b159ed7f8550388c04758
BLAKE2b-256 checksum
How to use checksums
205817b838e16ff0b037185f0b03335dce68ec55752ff7cb48a63407591289c5
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.

Transparency log

Security for secapi-py 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for secapi_py-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Jun 29, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page