Ga naar inhoud
REST · MCP · read-only

Developers

Belgian company data your software can read: identity and status from the KBO/BCE register, the verified act timeline extracted from the Belgisch Staatsblad / Moniteur belge, officers with currency semantics, and parsed NBB annual accounts. Two surfaces over the same corpus, one API key for both: a JSON REST API for conventional clients, and a Model Context Protocol endpoint for AI agents.

This reference is English only, on purpose: every identifier, tool name and error string in the surface below is English. The product itself is Dutch, French and English.


The provability promise

Every fact we serve carries the identifier of the document it came from, so your users can check it and your agent can cite it:

  • Act-derived facts carry numac, the Belgian gazette publication number, plus the publication date.
  • Mandates carry the numac and publication date of the act that established them.
  • Register facts (name, legal form, seat, status, NACE) come from the KBO/BCE open data.
  • Financial figures are the lines as filed with the National Bank; ratios are derived from them and labelled as derived.

The other half of the promise is admitting what is missing. Deep act extraction does not cover the whole corpus yet, so the MCP surface exposes get_extraction_status: it tells you how many gazette acts are on file for a company and how many have been extracted, so an empty timeline is explainable rather than mysterious. Sector-inapplicable financial ratios come back as an explicit not-applicable marker with a reason, never as a misleading number.


Basics
REST base URLhttps://checked.be/api/v1
MCP endpointhttps://checked.be/mcp
AuthenticationX-Api-Key request header, on both surfaces
FormatJSON. REST fields are snake_case; MCP tool results are camelCase (the two serializers differ, this is not a typo)
MethodsRead-only. Every documented endpoint is a GET; MCP is JSON-RPC over POST but exposes no write tool
Rate limit60 requests per minute (see the rate-limit section, the two surfaces count differently)
CORSNot enabled. Call from your server, not from a browser
CachingEvery /api/v1 response carries Cache-Control: public, max-age=300
OpenAPINone published. This page is the specification
VersioningIn the path (/v1/). Additive changes ship without a version bump; see the changelog

Authentication

Send your key in the X-Api-Key header. There is no bearer-token form and no query-string form. Keys are issued by hand today: mail enterprise@checked.be and say what you are building. There is no self-service key page yet, and this reference will not pretend otherwise.

curl -sS -H "X-Api-Key: $CHECKED_API_KEY" \
  https://checked.be/api/v1/companies/0400378485

The gate is fail-closed: if no keys are provisioned on the server, every call gets 401, including calls that carry a key.


REST endpoints

Four endpoints. The {kbo} path segment accepts any form whose digits end in a 10-digit enterprise number: 0400378485, 0400.378.485 and BE0400378485 all resolve to the same company.

GET /api/v1/companies/{kbo}

The dossier spine: identity, seat, risk band, insolvency rollup and the mandate list. risk is never null (an unscored company gets band Unknown with score 0); rollup and address are null when we hold nothing. band is PascalCase and one of Unknown, Low, Moderate, Elevated, High, Severe.

{
  "enterprise_number": "0400378485",
  "legal_name": "COLRUYT GROUP",
  "legal_form": "610",
  "primary_nace": "47110",
  "status": "active",
  "address": { "street": "...", "zip": "1500", "city": "Halle" },
  "risk": {
    "band": "Low", "score_out_of100": 88, "probability": 0.0121,
    "altman_z": 3.42, "model_version": "...", "evaluated_at": "2026-07-30T02:11:04+00:00"
  },
  "rollup": null,
  "insolvency_event_count": 0,
  "admin_event_count": 4,
  "mandates": [
    { "role": "...", "role_kind": "...", "name": "...", "address": null,
      "from": "2019-05-14", "to": null, "source": "...", "source_numac": "2019..." }
  ]
}
GET /api/v1/companies/{kbo}/lifecycle

A bare JSON array of legal-lifecycle events, no envelope. source is one of faillissement, reorg, insolvency_interim, kbo_admin; severity is low, med or high. Not paginated: you get the whole timeline.

[
  { "source": "faillissement", "severity": "high", "numac": "2026...",
    "pub_date": "2026-05-20", "event_kind": "...", "court": "...",
    "event_date": "2026-05-14", "detail": "..." }
]
GET /api/v1/companies/{kbo}/rollup

The compact insolvency aggregate on its own, for cheap screening of a portfolio. Returns 404 when the company exists but has no rollup on file.

{
  "total_events": 3, "interim_signals": 1, "reorg_events": 1,
  "faillissement_events": 1, "first_signal_date": "2026-01-05",
  "last_signal_date": "2026-05-20", "has_open_faillissement": true
}
GET /api/v1/search?q={query}&limit={n}

Company lookup by name, enterprise number, VAT number or NACE code. limit defaults to 20 and is clamped to 1..50. A blank or missing q returns [] with status 200, not an error. Not paginated and no total count: this is a resolver, not a corpus dump. match_kind tells you which lane matched (name, address, kbo, nace). On this endpoint kind is always company and href/subtitle are always null; they exist so the shape matches the internal omni-search wire format.

curl -sS -H "X-Api-Key: $CHECKED_API_KEY" \
  'https://checked.be/api/v1/search?q=colruyt&limit=5'

[
  { "enterprise_number": "0400378485", "legal_name": "COLRUYT GROUP",
    "slug": "colruyt-group-0400378485", "city": "Halle", "primary_nace": "47110",
    "match_kind": "name", "matched_address": null, "kind": "company",
    "href": null, "subtitle": null }
]

Errors

Every error carries a JSON body with a single error string. Match on the status code, not on the wording.

401{"error":"Missing X-Api-Key header."}
401{"error":"Invalid API key."}
401{"error":"API access is not enabled."}
404{"error":"Unknown enterprise number."}
429{"error":"Rate limit exceeded: ..."} plus Retry-After: 60

Rate limits
REST /api/v1/*60 requests per minute, counted per client IP, fixed window
MCP /mcp60 requests per minute, counted per API key when a key is present, otherwise per IP
Over the limit429 with Retry-After: 60
Repeated bad keysMore than 20 failed /mcp authentications in a minute from one IP get 429 instead of 401

One caveat worth knowing before you build a batch job: the REST budget is per IP and is shared with the unauthenticated /internal/search and /health/status endpoints. If you need sustained throughput, higher limits are a mail away rather than something to work around.


Model Context Protocol

https://checked.be/mcp speaks MCP over streamable HTTP: JSON-RPC 2.0 on POST, an event stream on GET, session id in the Mcp-Session-Id header. Protocol versions 2024-11-05 through 2025-11-25 are negotiated at initialize. Server identity is Checked.be version 1.0.0. The legacy HTTP+SSE transport is disabled, so that one path is the entire surface: there are no separate stream or message endpoints to configure. Six tools, no resources, no prompts, nothing that writes.

The endpoint requires the same X-Api-Key header as the REST API. A client configuration without it will fail at initialize with a 401.

{
  "mcpServers": {
    "checked": {
      "type": "http",
      "url": "https://checked.be/mcp",
      "headers": { "X-Api-Key": "your-key" }
    }
  }
}

Key name and nesting differ per client (some use servers rather than mcpServers); the URL, the transport type and the header are what matter.

Tools
search_companies
query, page
Resolve a name, enterprise number, VAT number or NACE code to companies. Ten hits per page, each with its canonical dossier URL. Start here, then feed enterprise_number to the other tools.
get_company_profile
kbo
Identity, status, seat, NACE, headline figures from the latest filed annual accounts, financial-health score and bankruptcy-probability band. Banks, insurers and holdings get explicit not-applicable fields instead of misread trading ratios.
get_company_acts
kbo, limit
The differentiator: the verified, per-act extracted gazette timeline. Typed facts with resolved actor names and amounts, every fact stamped with its numac. Newest first, 1 to 100 acts.
get_company_officers
kbo
Board and mandates with currency semantics: current, stale (open per the register but not re-confirmed recently) or former, plus corporate officers, permanent representatives and statutory auditors. Never includes birth dates or national numbers.
get_company_financials
kbo, year
Parsed NBB figures and derived ratios per fiscal year, sector-aware. The free scope returns the latest fiscal year only; older years are gated and the tool says so in its note rather than returning silence.
get_extraction_status
kbo
How many gazette acts are on file for this company and how many have been extracted, plus the queue state. Call it whenever an act timeline looks empty or short.

Every tool result carries a source attribution string and, where relevant, a dossierUrl a human can open. National register numbers are stripped from every field before serialization.


Machine surfaces that need no key
GET /healthzLiveness. Always 200, no dependencies, never cached
GET /health/statusReadiness: database, Argus views and job-server probes plus data freshness. 200 even when degraded
GET /versionRelease id, commit hash and build timestamp of the running build
GET /sitemap.xmlSitemap index; sub-sitemaps are crawl-priority ordered with real lastmod dates
GET /robots.txtCrawler policy, including the named AI-crawler sections
GET /insolventies/rss.xmlNewest insolvency publications as RSS 2.0
GET /badge/{kbo}.svgEmbeddable status badge for one company
GET /export/company/{kbo}/financials.csvParsed annual-account lines for one company as CSV
GET /kbo/{kbo}301 to the canonical dossier URL. Handy for deep links when you only hold a number

Changelog

Breaking changes get a new path version and are announced to every key holder by mail before they ship. Additive changes (new fields, new MCP tools) land in v1 and are listed here, so write tolerant parsers.

2026-08-09 REST error responses now always carry a JSON body: 404 and 429 used to return an empty body, which the site's not-found handler turned into an HTML page. No field or route changed. First publication of this reference.
2026-07 MCP endpoint live with six read-only tools, key-gated, 60 requests per minute per key.
2026-06 /api/v1 live: dossier, lifecycle, rollup and search, key-gated.

Need a key, higher limits or bulk access?
Tell us what you are building. Keys are issued by hand, which means you get a human answer rather than a form.
enterprise@checked.be

Short marketing overview of the same API: the API page. Where the data comes from: sources. How we score: methodology. Browse the corpus: company search.