Errors
Every error the API returns shares a single envelope, so a client can always surface one human-readable message — even for validation failures:
detail— a human-readable message; always present.code— a stable machine code you can branch on.errors— present for validation failures: the offending fields and why.
Branch on code, not on detail. Messages are written for humans and may be
reworded; codes are part of the contract.
Status codes in an ingestion context
Error responses never leak internal detail.
What a 422 means for events
An event body is rejected as a whole. The usual causes, in rough order of how often they bite:
- A missing required field.
event_id,event_name,event_timeandanonymous_idare all required on every event. Omitting any one is a422. event_timein milliseconds. It must be Unix time in seconds (a float is fine). A millisecond value is not a validation error in itself, but it is the most common reason events land at an absurd timestamp.- An illegal
event_name. It must match^[a-zA-Z0-9_.]{1,128}$— no spaces, no hyphens. - Oversized
properties. The JSON-encoded object is capped at 64,000 bytes. Send identifiers, not payload dumps. - More than 500 events in a
/batchrequest.
The errors array names the offending field, so log it rather than just the
status.
A 422 is permanent. Retrying an identical body will fail identically — fix the
payload instead. The SDKs encode this: 4xx responses other than 429 stop the
retry loop immediately.
Rate limits and 429
There are two independent budgets, and they count different things:
- Per IP — counts requests. A batch of 500 events costs one.
- Per workspace — counts events. A batch of 500 events costs 500.
Which one you hit is stated in the response, so you don’t have to guess:
The distinction drives the fix. (IP) means too many requests from one address
— batch your sends via /batch, which collapses up to
500 events into a single request. (workspace) means genuine event volume, and
batching won’t help at all; you’re sending more events than the workspace is
provisioned for.
Unlike other 4xx responses, a 429 is retryable. Back off and resend with the
same event_id — deduplication is keyed on (workspace, event_id), so a
resent event is recorded once and comes back as {"duplicate": true}.
Related
- Sending events over HTTP — the endpoints, the required fields, and the response envelope.
- Authentication — the difference between the two write
key types that
403is telling you about.