Documentation
Three tools, one asynchronous pattern, a stable set of error codes. This page is the whole
contract.
Connecting
Client-by-client instructions are on the setup pages. A request
without a key gets 401 with a WWW-Authenticate header; a key over the
rate limit gets 429 with Retry-After.
The asynchronous pattern
Fetching a filing means calling the National Bank, downloading a deposit and parsing XBRL — too
slow to hold a tool call open, and far too slow when the filing is a PDF that needs an LLM. So
get_annual_accounts hands back an operation and you poll it.
-
Call
get_annual_accounts. Normally you get
{"operation_id": "…", "status": "pending", "poll_after_seconds":
3}.
-
Wait
poll_after_seconds, then call get_operation with that id.
Repeat while the status is pending or processing.
-
Stop at
completed (the accounts are in result) or
failed (there is an error object with a code from the table
below).
Two shortcuts are built in. A filing that is already cached comes back from
get_annual_accounts immediately with status: "completed" and
cached: true — no polling. A cached filing whose JSON is too large to inline
(over 100 KB, which happens with raw: true) comes back as an operation with
cached: true, and the first poll answers instantly.
Do not re-request while an operation is running. Identical requests are
de-duplicated server-side: asking again returns the same operation id and spends another
billable call for nothing.
Operations belong to the API key that created them. Polling somebody else's id answers exactly
like polling a nonexistent one. Finished operations are cleaned up 30 days after they finish.
Error codes
A failed operation carries error.code, and these strings are stable — a client may
branch on them.
Errors that are not operation failures
Bad input, an exhausted quota and an unknown operation id come back as a tool error
(MCP isError: true) with an explanatory message rather than as an operation you can
poll — there is nothing running to poll.
Limits
Quotas reset on the 1st of each month.
The result JSON
Every completed get_annual_accounts result has the same shape:
Languages
language accepts nl, fr, de and
en, and defaults to nl. Labels come from the National Bank's own
taxonomy label linkbases, not from a translation engine, so they match the wording on the
official forms.
If a label is missing in the language you asked for, the response falls back in order: requested
language → the language the filing was submitted in → nl → fr → en. The figures never change with
the language, and meta.response_language tells you what you actually got.
Data sources and caveats
meta.data_source says how a result was produced, and it is the field to read before
trusting a number:
Known caveats
-
Only filings the National Bank has accepted are served. A deposit that was corrected
later resolves to the correction, not the original.
-
Company-name search uses the KBO/BCE open-data denomination file, refreshed monthly. A company
registered in the last few weeks may be findable by number before it is findable by name.
-
Several companies can share a name.
search_company returns candidates with a
match score and expects the caller to disambiguate rather than guess.
-
Older filings use earlier taxonomy generations. Where a generation is not yet mapped, the
response says so (
pdf_fallback_required) instead of returning partial figures.
-
This service is not affiliated with the National Bank of Belgium and adds no interpretation:
what is filed is what you get, including any errors the filer made.