APIs · Business
Documents API
The original files behind every filing and investor-relations publication — PDF, HTML, XBRL and report packages exactly as the issuer or regulator published them — listed by one cross-market taxonomy and downloadable in bulk.
Endpoints
| MCP | HTTP |
|---|---|
| — (REST) | GET /api/v1/documents/taxonomy Categories (grouped), IR document types and subtypes, archive statuses, with counts. |
| — (REST) | GET /api/v1/documents?ticker=&market=|isin=|lei=&category=&from=&to=&archived=true Documents of an issuer, a market or a category — newest first, cursor-paginated. |
| — (REST) | GET /api/v1/documents/{id} Metadata, files (primary, attachments) and the list of files inside a package. |
| — (REST) | GET /api/v1/documents/{id}/content[?file_id=] 302 redirect to a short-lived download link for the file. |
Use cases
Discover what exists: GET /documents/taxonomy returns the categories every document is filed under (annual_report, interim_report, earnings_release, proxy, insider_transaction, …) in seven groups — the same vocabulary for regulator filings and IR publications.
Pull an issuer's history: list by issuer and category — for example every annual report of Toyota — then download each file. Regulator filings and IR publications come back together; origin tells them apart.
Archive or re-process originals: every file carries a sha256 of its exact bytes, so you can deduplicate, verify integrity and prove provenance against the issuer's own copy.
Read inside packages: DART, ESEF and XBRL filings are ZIP packages. The document detail lists every file inside (path, type, size) before you download the package.
Identifying the issuer
Same identifiers as the rest of the API and the MCP server. A ticker reused across markets (7203, 005930, AAPL on several venues) must be paired with market; otherwise the call answers 400 with the candidate markets. Unknown identifiers answer 404.
| Parameter | Example | Notes |
|---|---|---|
| ticker + market | ticker=7203&market=jp | Exchange symbol + market id from GET /api/v1/markets. |
| isin | isin=US0378331005 | Any listing ISIN of the issuer. |
| lei | lei=549300EX04Q2QBFQTQ27 | All the issuer's documents, every listing. |
| canonical_key | canonical_key=sec:0000320193 | From /entities/search or a previous response. |
| market (alone) | market=kr&category=annual_report | Browse a whole market instead of one issuer. |
Filters
| Parameter | Values |
|---|---|
| category | Repeatable: category=annual_report&category=interim_report (see taxonomy). |
| category_group | periodic · corporate_action · mna · ownership · capital · governance · other |
| origin | filing (regulator) · ir (issuer website) |
| native_type / subtype | Form type as filed (10-K, 6-K, ANNUAL…) / IR subtype (esg, agm, guidance…). |
| from / to | Document date, YYYY-MM-DD. |
| archived | true = only documents whose file is ready to download. |
| limit / cursor | Up to 200 per page; pass next_cursor to continue. |
Response
Each item carries the issuer (company_name, canonical_key, ticker, market_id), the taxonomy (category, category_label, category_group, native_type, subtype), dates (document_date, period_end), display_title, source_url (the issuer's or regulator's page) and an archive block.
archive.status: stored — the file is downloadable; pending — known, not fetched yet; not_a_document — the record is structured data with no file of its own (for example one line of an exchange delisting list); unresolved — the source does not expose the file to us yet; failed / exhausted / too_large — the fetch did not succeed. archive.content_type, byte_size and sha256 describe the stored file.
Downloading
GET /documents/{id}/content answers 302 with a link valid for 10 minutes; follow the redirect. The file name is set for you ({ticker}_{form}_{date}.{ext}).
Text files (HTML, XML, JSON, CSV) are sent with Content-Encoding: gzip. Browsers, Python requests/httpx and most SDKs decode it automatically; with curl add --compressed, with wget add --compression=auto. The sha256 in the metadata is the one of the decoded file.
Files inside a package are listed but not served one by one: download the package itself (content without file_id) and open it locally. Attachments (for example the PDFs of a KAP disclosure) are downloadable with their file_id.
# 1. find the documents
curl -s -H "X-API-Key: of_your_key" \
"https://api.openfilings.org/api/v1/documents?ticker=AAPL&market=us&category=annual_report&archived=true&limit=5"
# 2. download one (follow the redirect, decode gzip)
curl -sL --compressed -OJ -H "X-API-Key: of_your_key" \
"https://api.openfilings.org/api/v1/documents/{id}/content"Status codes
| Status | Meaning |
|---|---|
| 200 / 302 | Metadata / redirect to the download link. |
| 400 | Listing not narrowed, invalid cursor, or ticker ambiguous across markets (add market). |
| 403 upgrade_required | Your plan does not include raw documents. |
| 404 | Unknown document or issuer; member_not_served for a file inside a package. |
| 409 not_archived | Catalogued but the file is not stored yet. Body: archive_status, retryable. |
| 429 download_quota_exceeded | Daily download allowance used; resets at 00:00 UTC. |
| 503 delivery_unavailable | Downloads temporarily unavailable; listing still works. Retry-After is set. |
Example
curl -s -H "X-API-Key: of_your_key" \ "https://api.openfilings.org/api/v1/documents?isin=KR7005930003&category=annual_report&archived=true"
Python SDK:
import httpx
API = "https://api.openfilings.org/api/v1"
H = {"X-API-Key": "of_..."}
page = httpx.get(f"{API}/documents", headers=H, params={
"ticker": "7203", "market": "jp", "category": "annual_report", "archived": "true",
}).json()
for doc in page["items"]:
r = httpx.get(f"{API}/documents/{doc['id']}/content", headers=H, follow_redirects=True)
open(doc["id"] + ".bin", "wb").write(r.content) # decoded; sha256 == doc["archive"]["sha256"]Notes
- Coverage grows continuously: archived=true returns what is downloadable today, and a document moves from pending to stored without changing id.
- Documents are not exposed through the MCP server — use REST.
- The daily file allowance is consumed only when a download link is issued (302); 404 and 409 answers are free.