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.
Metadata
Release files for openfilings 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| openfilings-0.1.0.tar.gz | 59.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| openfilings-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 86.3 kB
Release files / openfilings-0.1.0.tar.gz
| Download URL | openfilings-0.1.0.tar.gz |
|---|---|
| Size | 59.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
833cc1d61b570a7476348e8d82f8d703a41e5b71906a2f3e4d6c279622e85464
|
|
BLAKE2b-256 checksum How to use checksums |
449c4a437338337282d68f3125810b852ebe74e3287cdb855d56609755ad4659
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / openfilings-0.1.0-py3-none-any.whl
| Download URL | openfilings-0.1.0-py3-none-any.whl |
|---|---|
| Size | 27.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
39d721246f9d482ab8e74b5526c960d1afc7f89404460a8bd6c821d861721862
|
|
BLAKE2b-256 checksum How to use checksums |
62356fde22463c20a9d73000b1a44c557f69be43f674dfa5d0499b3c69c08a2c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|