Errors & Limits
Errors & Limits
Every non-2xx response from the API carries the same machine-readable envelope, every request gets a correlation ID you can quote to support, and the request limits are fixed and documented. This page is the reference for all three.
The ApiError envelope
codeis the stable, machine-readable value to branch on — codes are additive-only and never renamed.messageis human-readable and actionable. It never leaks internals (no stack traces, no provider errors).correlationIdalways echoes the request’s correlation ID.ruleIdis set when a policy rule denied the request; otherwisenull.
Error codes
Unmatched routes return 401, by design: the API denies by default, so a typo’d path looks like an auth failure rather than a 404. If a request 401s unexpectedly, check the path first.
Correlation IDs
Every request is assigned a correlation ID of the form req_ followed by
exactly 32 hex characters. You can supply your own on the X-Correlation-Id
request header — if it matches that format it is honored verbatim; anything
else (or no header) is replaced with a freshly minted ID. A bad value is
never a rejection.
The established ID is echoed back on the X-Correlation-Id response header
and inside every error body. Log it, and quote it in support requests —
it is how we find your request in our logs, and for a 500 internal.error it
is the only handle there is.
Request limits
Rate limiting at the edge
The platform edge (WAF) applies a per-IP limit of 2000 requests per
5-minute window. Requests over the limit are blocked at the edge with a
plain 403 — without the ApiError envelope. That is how you tell the two
403s apart:
- 403 with a JSON body and a
code— an API authorization failure (auth.insufficient_scope/auth.unknown_client). Fix the token or credential; retrying won’t help. - Bare 403 with no envelope — the edge rate limit. It clears on its own once your request rate drops below the limit. Back off and retry with jitter.
Two layers of “rejected” on /v1/events
/v1/events has a second, per-event rejection layer that is not an HTTP
error: individually invalid events come back inside the 200 response’s
rejected[] array with their own code vocabulary (event.*), while the
ApiError envelope covers batch-level failures only. The split — and the five
per-event codes — are covered in the
behavioral events guide.