openfilings
Official Python client for the OpenFilings API — primary-source regulatory filings, canonical cross-GAAP KPIs, and signed push webhooks across 16 markets (US, EU/ESEF, UK, Japan, Hong Kong, South Korea, China, Taiwan, India, Singapore, Australia, Canada, Brazil, Israel, UAE, Saudi Arabia).
pip install openfilings
Quickstart
from openfilings import Client
client = Client(api_key="of_...") # or set OPENFILINGS_API_KEY
entity = client.entities.search(ticker="AAPL").entity
print(entity.canonical_key, [l.market_id for l in entity.listings])
filings = client.filings.list("AAPL", market_id="us", limit=5)
for f in filings.filings:
print(f.form_type, f.filing_date, f.id)
financials = client.companies.financials(
ticker="AAPL",
market_id="us",
fiscal_year_from=2020,
fiscal_year_to=2024,
line_items=["revenue", "ebitda", "gross_margin"],
)
for period in financials.periods:
print(period.fiscal_year, period.values)
Get an API key from your dashboard: My Page → API Keys on
openfilings.org. Every response is a thin wrapper: documented fields
are plain attributes (entity.canonical_key), and .raw / .to_dict() always has the full JSON —
so a new field the API starts returning tomorrow is reachable today without an SDK upgrade.
Async
AsyncClient mirrors Client one-to-one:
import asyncio
from openfilings import AsyncClient
async def main() -> None:
async with AsyncClient(api_key="of_...") as client:
markets = await client.markets.list()
print(markets.allowed_market_ids)
asyncio.run(main())
Resources
| Resource | Purpose |
|---|---|
client.markets.list() |
Markets enabled on your plan — call first |
client.entities.search(...) / .lookup(...) |
Resolve a company by name, ticker, LEI, or ISIN |
client.filings.discover(...) |
Cross-market filing discovery, one call |
client.filings.list(ticker, ...) |
Filing history for one ticker/market |
client.filings.resolve(...) |
Resolve one specific filing |
client.filings.search(q, ...) |
Full-text search over filing section bodies |
client.filings.kpis(filing_id) |
Canonical, cross-GAAP KPIs for one filing |
client.filings.sections(filing_id) / .section(filing_id, key) |
Narrative sections (Item 1A, MD&A, …) |
client.companies.financials(...) |
Multi-year period series, no per-filing loop |
client.companies.earnings(market, ticker) |
Street upcoming/recent earnings |
client.companies.supply_chain(market, ticker) |
Named + anonymous supply-chain edges |
client.companies.kpi_taxonomy() |
Valid line_items codes |
client.notifications.list(...) |
Your alert inbox |
client.watchlist.list() / .add(...) / .update(...) / .remove(...) |
Followed tickers |
client.press.list_for_ticker(...) / .insider_transactions(...) |
Wire headlines + Form 4 (Pro+) |
client.webhooks.list() / .create(...) / .update(...) / .delete(...) / .test(...) |
Manage push endpoints (Business) |
Webhooks
Business plan accounts can register a URL that receives a signed POST within seconds of a new
filing, press release, or insider transaction matching your watchlist:
client.webhooks.create(
"https://yourapp.example.com/openfilings-webhook",
event_types=["filing.discovered"],
secret="whsec_...", # returned once — store it, later reads redact it
)
Verify deliveries with zero extra dependencies — openfilings.webhooks only needs the
standard library, so it works in a Lambda handler without the rest of the SDK installed.
Recommended — FastAPI (pip install openfilings[fastapi]):
import os
from fastapi import Depends, FastAPI
from openfilings import Client
from openfilings.integrations.fastapi import openfilings_webhook_dependency
from openfilings.webhooks import WebhookEvent
app = FastAPI()
client = Client() # OPENFILINGS_API_KEY
verify = openfilings_webhook_dependency(os.environ["OPENFILINGS_WEBHOOK_SECRET"])
@app.post("/openfilings-webhook")
async def on_filing(event: WebhookEvent = Depends(verify)) -> dict:
if event.event == "filing.discovered":
kpis = client.filings.kpis(event.data["filing_id"])
# ... run your signal ...
return {"ok": True}
Also Flask (pip install openfilings[flask]):
from openfilings.integrations.flask import verify_flask_webhook
event = verify_flask_webhook(request, SECRET)
Or call verify_webhook(raw_body, headers, secret) directly with the stdlib helper.
See examples/fastapi_webhook.py and
examples/flask_webhook.py for complete handlers, and
openfilings.org/docs/webhooks for the full event catalog,
payload envelope, and retry policy.
Signature scheme
X-Webhook-Signature: sha256=<hex>X-Webhook-Timestamp: <ISO 8601 UTC>— same value embedded in the JSON body'stimestamp- Signature =
HMAC-SHA256(secret, f"{timestamp}." + raw_body_bytes) - Envelope:
{"event": "...", "version": "1", "timestamp": "...", "data": {...}}
Always verify against the raw request body bytes — re-serializing the parsed JSON before verifying will break the signature if key order or whitespace differs.
Error handling
from openfilings import Client, QuotaExceededError, UpgradeRequiredError, NotFoundError
client = Client(api_key="of_...")
try:
client.press.list_for_ticker("AAPL")
except UpgradeRequiredError as exc:
print(f"needs {exc.min_plan} plan — feature: {exc.feature}")
except QuotaExceededError as exc:
print(f"quota exceeded ({exc.dimension}); retry after {exc.retry_after}s")
except NotFoundError:
print("not found")
All exceptions inherit from openfilings.OpenFilingsError. HTTP 429 with a short Retry-After
(≤ 5s) is retried automatically (2 attempts by default, tune with max_retries=); longer waits —
e.g. a daily quota reset — surface as QuotaExceededError instead of blocking your process.
Configuration
| Environment variable | Purpose | Default |
|---|---|---|
OPENFILINGS_API_KEY |
X-API-Key sent on every request |
— |
OPENFILINGS_BASE_URL |
API base URL | https://api.openfilings.org |
Both can be overridden per-client: Client(api_key=..., base_url=...).
Links
- Documentation
- REST API reference
- Webhooks guide
- Pricing
- Source (this repo is a read-only mirror of the SDK subtree in the main monorepo)
- Issues / feature requests
License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file openfilings-0.1.0.tar.gz.
File metadata
- Download URL: openfilings-0.1.0.tar.gz
- Upload date:
- Size: 59.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
833cc1d61b570a7476348e8d82f8d703a41e5b71906a2f3e4d6c279622e85464
|
|
| MD5 |
3d27cf8a639bf3332e3366df54d8f315
|
|
| BLAKE2b-256 |
449c4a437338337282d68f3125810b852ebe74e3287cdb855d56609755ad4659
|
File details
Details for the file openfilings-0.1.0-py3-none-any.whl.
File metadata
- Download URL: openfilings-0.1.0-py3-none-any.whl
- Upload date:
- Size: 27.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.30 {"installer":{"name":"uv","version":"0.9.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Debian GNU/Linux","version":"12","id":"bookworm","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
39d721246f9d482ab8e74b5526c960d1afc7f89404460a8bd6c821d861721862
|
|
| MD5 |
25d660721da56e86790b644c53e40e59
|
|
| BLAKE2b-256 |
62356fde22463c20a9d73000b1a44c557f69be43f674dfa5d0499b3c69c08a2c
|