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.

Business plan only. Listing and metadata calls use your normal API credits. Other plans receive 403 upgrade_required.

Endpoints

MCPHTTP
— (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.

ParameterExampleNotes
ticker + marketticker=7203&market=jpExchange symbol + market id from GET /api/v1/markets.
isinisin=US0378331005Any listing ISIN of the issuer.
leilei=549300EX04Q2QBFQTQ27All the issuer's documents, every listing.
canonical_keycanonical_key=sec:0000320193From /entities/search or a previous response.
market (alone)market=kr&category=annual_reportBrowse a whole market instead of one issuer.

Filters

ParameterValues
categoryRepeatable: category=annual_report&category=interim_report (see taxonomy).
category_groupperiodic · corporate_action · mna · ownership · capital · governance · other
originfiling (regulator) · ir (issuer website)
native_type / subtypeForm type as filed (10-K, 6-K, ANNUAL…) / IR subtype (esg, agm, guidance…).
from / toDocument date, YYYY-MM-DD.
archivedtrue = only documents whose file is ready to download.
limit / cursorUp 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

StatusMeaning
200 / 302Metadata / redirect to the download link.
400Listing not narrowed, invalid cursor, or ticker ambiguous across markets (add market).
403 upgrade_requiredYour plan does not include raw documents.
404Unknown document or issuer; member_not_served for a file inside a package.
409 not_archivedCatalogued but the file is not stored yet. Body: archive_status, retryable.
429 download_quota_exceededDaily download allowance used; resets at 00:00 UTC.
503 delivery_unavailableDownloads 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.