Errors & back-off

Quotas, errors, and recommended back-off

OpenRegistry surfaces three distinct kinds of failure with structured responses so AI agents can branch on them: rate limits (429), statutorily-restricted registers (501 by design), and upstream errors (5xx). Honour the structured retry hints — don't add ad-hoc exponential back-off on top.

Rate limits

Per-IP for anonymous, per-user for signed-in. The cross-border fan-out cap is a separate counter that limits how many distinct jurisdictions a caller can hit via search_companies in a rolling 60-second window.

When you exceed either limit, the response is HTTP 429:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32000,
    "message": "rate-limited",
    "data": {
      "reason": "rate-limited",
      "retry_after_ms": 12400,
      "scope": "ip"           // or "user" or "fanout"
    }
  }
}

The HTTP layer also sets the standard Retry-After: 13 header (seconds, rounded up). Honour retry_after_ms exactly — exponential back-off on top is unnecessary; the limit window is fixed-rolling, not adaptive. Fan-out cap (scope: "fanout") is a 60-second rolling window — the second your oldest country falls off, you can hit a new one. Pro tier caps at 10 distinct countries / 60s, Max at 30, Enterprise unlimited.

Statutorily restricted (CJEU C-37/20 and similar)

Some beneficial-ownership registers became access-restricted to AML-obliged entities post-CJEU C-37/20 (DE, ES, IT, NL, LU, AT, MT, PT) and the Cayman Beneficial Ownership Transparency Act 2023. We don't proxy these — the tool returns HTTP 501 with structured guidance:

{
  "jurisdiction": "DE",
  "error": "not_proxied_by_design",
  "reason": "CJEU-C-37-20",
  "alternative_url": "https://www.transparenzregister.de",
  "alternative_access": "AML-obliged entities only (banks, lawyers, notaries, etc.)",
  "human_message": "The German Transparency Register is statutorily gated since 22 Nov 2022."
}

This is a design response, not a transient failure — retrying won't help. The alternative_url is the canonical statutory portal where qualified entities can register for access.

Upstream errors and tool-level structured 501s

When the upstream registry has its own outage, we surface its error verbatim with a structured wrapper:

{
  "jurisdiction": "ES",
  "error": "upstream_error",
  "upstream_status": 524,
  "human_message": "Spain BORME upstream timed out (Madrid bulletin renderer slow). Retry in 30-60s.",
  "retry_after_ms": 45000
}

Some tools also return 501 with an alternative tool suggestion when the upstream registry doesn't expose the requested concept (e.g. CZ political parties don't have officers in the standard sense — call search_specialised_records with source="rpsh" instead):

{
  "error": "alternative_tool_required",
  "alternative_tool": "search_specialised_records",
  "alternative_args": { "jurisdiction": "CZ", "source": "rpsh", "...": "..." },
  "human_message": "Czech political parties register is exposed via the RPSH sub-source."
}

Recommended client back-off

ErrorAction
429 rate-limitedSleep retry_after_ms, then retry once.
429 fanoutDon't retry the same call; route the next request to a country you've already hit in the window.
501 not_proxied_by_designDon't retry. Surface alternative_url to the user.
501 alternative_tool_requiredRe-issue with alternative_tool + alternative_args.
5xx upstream_errorSleep retry_after_ms if present, else 30s. Max 3 retries.
4xx not_foundDon't retry. Re-search with search_companies to discover a valid id.

Reference back-off implementations are published in every framework integration guide under /docs/integrations.