Skip to content
Subsido

Using the API

Errors

One error shape on every route. Branch on error.code: codes never change, messages may be reworded.

The envelope

{
  "error": {
    "code": "plan_required",
    "message": "'history' requires the pro plan or above.",
    "request_id": "req_0192d3a4b5c67d8e9f0a1b2c3d4e5f65",
    "details": {
      "capability": "history",
      "required_plan": "pro"
    },
    "required_plan": "pro"
  }
}
  • code is stable and machine-readable. message is for a person, in English, and names what was wrong: the parameter, the value, what was expected.
  • request_id is also in the X-Request-Id header. Quote it when you write to us: it is the id in our logs.
  • details is always an object, empty when there is nothing to add. required_plan appears only on plan_required.
  • A 429 carries Retry-After in seconds.
{
  "error": {
    "code": "invalid_body",
    "message": "company.postcode: company.postcode is not a Belgian postcode",
    "request_id": "req_0192d3a4b5c67d8e9f0a1b2c3d4e5f66",
    "details": {
      "field": "company.postcode"
    }
  }
}
{
  "error": {
    "code": "plan_required",
    "message": "companies=800 is above the 500 this plan allows. The enterprise plan or above allows it.",
    "request_id": "req_0192d3a4b5c67d8e9f0a1b2c3d4e5f67",
    "details": {
      "capability": "companies_max",
      "parameter": "companies",
      "requested": "800",
      "allowed": "500",
      "required_plan": "enterprise"
    },
    "required_plan": "enterprise"
  }
}

400 or 422

400 invalid_parameter means the request could not be read as asked: an unknown or repeated query parameter, a value outside its vocabulary, a limit above your plan, or a JSON body that does not parse, has a property the route does not know, or a value of the wrong type. 422 invalid_body means the body was read and says something that cannot be right: a postcode that is not Belgian, an enterprise number whose check digits fail, a negative budget. details.field names the property.

Every code

Request

Request errors
CodeStatusWhenWhat to do
invalid_parameter400A query parameter is malformed, out of range, repeated, or not a parameter of the route; a vocabulary value is not one of its members; a limit is above your plan's page size; or a JSON body does not parse, has a property the route does not know, or has a value of the wrong type.The message names the parameter and what was expected. Fix the request: retrying it unchanged fails the same way. Unknown parameters are refused rather than ignored, so a typo never silently widens a result.
invalid_cursor400The cursor is not one the API issued, or was issued for a different listing or sort order.Start again without a cursor. The API refuses rather than silently restarting at page one.
invalid_body422A JSON body parsed but says something impossible: an enterprise number that fails its check digits, a postcode that is not Belgian, an invalid NACE code, an unknown legal form, a negative amount, a limit out of range, a duplicate reference.details: field: the property at fault, for example company.postcode.Correct the property named in details.field.
route_not_found404No endpoint exists at this path. The answer is still JSON in the error envelope.Check the path against /v1/openapi.json.
method_not_allowed405The path exists but does not take this method, for example a GET on /mcp.The Allow header lists the methods the path takes.

Key and plan

Key and plan errors
CodeStatusWhenWhat to do
unauthorized401The key is missing, malformed or revoked, on a route that needs one.Send Authorization: Bearer with a live or test key from the dashboard.
subscription_required402The key's account has no plan yet. It can sign in and create keys, but no key serves data until a plan is chosen.Choose a plan in the dashboard. The same key works as soon as the plan is active.
plan_required403The route needs a capability your plan does not include (the change feed, history, as_of, webhooks, bulk matching, watchlists, the bulk export), or a number is above what your plan allows (companies in a bulk match, companies across your watchlists, webhook endpoints).details: capability and required_plan for a missing capability; for a number above the plan, also parameter, requested and allowed. error.required_plan repeats the plan.required_plan is the cheapest plan that would have answered. Upgrade, or leave the feature out.

Data

Data errors
CodeStatusWhenWhat to do
subsidy_not_found404No measure has this id or slug.details: subsidy: the id or slug you asked for.GET /v1/subsidies lists them. A measure merged into another keeps resolving to the one it was merged into, so an old id is not a reason for this.
version_not_found404The measure exists, but not the version you asked for, or it did not exist yet at the as_of instant.The message says which version is current, or when the first version is from.
source_not_found404No source has this id. Also answered when a webhook filter names an unknown source.details: source: the id you gave.GET /v1/sources lists them.
watchlist_not_found404No watchlist with this id belongs to your account. Also answered when a webhook filter names one.GET /v1/watchlists lists yours.
webhook_not_found404No webhook endpoint with this id belongs to your account.GET /v1/webhooks lists yours.
not_found404The company reference you asked to remove is not on the watchlist.GET /v1/watchlists/{id}/companies lists the references on it.
conflict409The request is valid but the state does not allow it, for example a 51st watchlist on one account.The message says why. Change the state first (delete a watchlist), then retry.

Limits

Limits errors
CodeStatusWhenWhat to do
rate_limit_exceeded429Too many requests per second for your plan (or, on the routes that need no key, for your address). Also answered when both bulk export download slots are in use.Wait the seconds in Retry-After (1, or 5 for the export). Page one request at a time rather than in parallel.
quota_exceeded429This month's request quota is used up.Retry-After counts the seconds to the start of the next UTC month. RateLimit-Remaining shows it coming.
match_quota_exceeded429This month's match evaluations are used up, or a bulk match or watchlist upload would take you past them. Reading measures still works.details: limit: your plan's monthly match evaluations.Retry-After counts the seconds to the next UTC month. A larger plan has a larger allowance. Nothing of a refused bulk request is evaluated or counted.

Server

Server errors
CodeStatusWhenWhat to do
internal_error500Something failed on our side. The detail is logged, never sent.Retry with backoff. If it persists, send us the request_id.
billing_unavailable503Card payment is not configured or the payment provider did not answer. Answered by the dashboard's billing routes only.Try again later, or write to us.
timeout504The request took longer than 30 seconds and was stopped. No route should come near it; the export streams.Retry it. A narrower filter or a smaller page answers faster.

Dashboard sign-in

Dashboard sign-in errors
CodeStatusWhenWhat to do
google_sign_in_failed401A Google sign-in token could not be verified.Sign in again.
password_sign_in_disabled403Password registration or sign-in was attempted on a deployment that offers Google sign-in only.Sign in with Google.

Good to know

  • Request bodies are limited to 2 MB.
  • Past authentication, the MCP endpoint answers protocol problems as JSON-RPC errors (HTTP 200, or 400 for a body that is not JSON), and a failed tool as a result with isError; see MCP.

Retrying

Retry 429 after Retry-After, and 500, 503 and 504 with exponential backoff. Do not retry 400, 401, 402, 403, 404 or 422 unchanged: the same request fails the same way.