You're viewing the reference. To execute live calls you need a Brubru API key: Start a Professional trial · or contact sales
Errors

Error responses

Every non-2xx response on /api/v2/* uses the same canonical envelope. Machine-readable reason_codes let you switch on error types without parsing free-text messages.

Error envelope

{
  "error": "Unauthorized: Missing API key",
  "reason_code": "auth_missing_key",
  "request_id": "f9e3a1b2-4c5d-6e7f-8a9b-0c1d2e3f4a5b"
}
FieldMeaning
errorHuman-readable message. Never parse this; use reason_code.
reason_codeStable machine-readable code. Safe to switch on.
request_idUUID4. Echoed in the X-Request-Id response header. Include this when emailing support.

HTTP status codes

CodeMeaning
200Success.
401Missing, malformed, or revoked API key.
403Key valid but owner is not on Professional, or account inactive.
404Resource not found.
422Invalid query parameter or conflicting params.
429Rate limit exceeded (60/min per key). See Retry-After header.
500Unhandled server error. Include request_id when reporting.
502Upstream EU portal temporarily unavailable.
503Derived computation unavailable (e.g. recital-article map failed to compute).

Reason codes

reason_codeStatusTrigger
auth_missing_key401No Authorization or X-API-Key header sent.
auth_invalid_format401Key doesn't start with brubru_live_.
auth_key_not_found401Key not in our DB or revoked.
tier_insufficient403Owner isn't on Professional.
org_inactive403Owner's account is disabled.
rate_limited429Over 60 requests per minute for this key.
not_found404Generic not-found (CELEX, procedure ref, MEP id, etc.).
text_unavailable404No text cached for the requested law and Cellar fallback also failed.
invalid_query422A query param failed validation.
conflicting_params422Two params that alias the same bound were sent with different values.
invalid_date_range422from is after to.
upstream_error502An EU source (HYS, Commission calendar, EP Open Data) returned an error.
computation_unavailable503Derived computation (recital-article map) failed for this CELEX.
internal_error500Unhandled exception on our side.

X-Request-Id header

Every response, successful or not, carries an X-Request-Id header. This equals the request_id in error bodies. When you report an issue, include it: we can find the exact request in our logs.

You can also supply your own X-Request-Id on the request; we honour it as long as it's ≤ 64 characters. Helpful for distributed tracing.

Recovery patterns

Rate limit (429)

Retry-After: 7
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0

Back off for Retry-After seconds. In Python:

if r.status_code == 429:
    time.sleep(int(r.headers.get("Retry-After", 60)))
    continue  # retry

Upstream error (502)

Something outside Brubru is broken (Have Your Say portal is down, Commission calendar is slow). Retry with exponential backoff up to 3 times. If it persists > 30 minutes, email us.

Conflicting params (422 conflicting_params)

You sent published_to AND published_end with different values. Pick one (prefer published_to) and retry.

Computation unavailable (503)

Specific to /legal-text/{celex}/recital-article-map. The TF-IDF parser can fail on edge-case XML. Fall back to /legal-text/{celex}/defined-terms which exercises a different parser. Email us the CELEX so we can debug.

Example error responses

Missing key:

HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="Brubru API"
X-Request-Id: 7f9e3c2b-1a4d-5b6c-7d8e-9f0a1b2c3d4e
Content-Type: application/json

{
  "error": "Unauthorized: Missing API key",
  "reason_code": "auth_missing_key",
  "request_id": "7f9e3c2b-1a4d-5b6c-7d8e-9f0a1b2c3d4e"
}

Conflicting params:

HTTP/1.1 422 Unprocessable Entity

{
  "error": "Conflicting upper-bound parameters: published_to=2026-01-01 and published_end=2026-03-31. They are aliases of the same bound; pass only one, or pass matching values.",
  "reason_code": "conflicting_params",
  "request_id": "..."
}

Rate limit:

HTTP/1.1 429 Too Many Requests
Retry-After: 12
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0

{
  "error": "Rate limit exceeded: 60 requests per minute",
  "reason_code": "rate_limited",
  "request_id": "..."
}

Next

See Rate limits for a full explanation of quotas and how to back off.