The envelope
Every non-2xx response has the same shape:erroris a stable enum. Match on it in code. We never change a code without a major version bump.messageis for humans. Show it in UIs. Wording may evolve; do not parse.trace_idis the support handshake. Quote it in any ticket — we resolve in one round trip.
X-Exorde-Trace-Id header.
Authentication errors
Sample:
Authorisation errors
upgrade_required carries upgrade context so a UI can render a CTA without a second roundtrip:
topic_denied echoes which topics you do have:
Resource errors
Validation errors
Pydantic-style detail when
validation_error:
Quota and rate-limit errors
rate_limited:
watchlist_limit_reached:
Server-side errors
service_unavailable:
Subscription / webhook errors
Webhook delivery (server-to-you, not request errors):
Verify the signature server-side before trusting the payload.
Common patterns
Match on error, not status
A 403 can be one of topic_denied, key_expired, key_revoked, upgrade_required, feature_disabled — all need different UX. Don’t hardcode “403 = upgrade prompt”; read error.
Always log trace_id
Distinguish “retry” from “act”
Encode this as a function:
Support handshake
When you email [email protected], include:- The full error envelope (especially
trace_id) - The exact request URL and method
- Your
client_id(from/v1/keys/current, not the api_key itself) - Approximate UTC timestamp
trace_id alone in most cases. The other fields are belt-and-braces.
Last reviewed: 2026-05-19. API version 1.2.8.