Reference
Error codes
Every failure from the public API has the same envelope, and the code inside it is stable. Branch on the code, never on the message: messages are written for humans and will be reworded.
The envelope
A failure returns an error object with a code, a human-readable message, and sometimes details. The code comes from one registry and is never invented at a call site, which is what makes it safe to switch on.
One entry per code
| Code | What causes it | Retry? |
|---|---|---|
| validation_failed | The body did not match the schema. Validation is per batch: one malformed event fails the whole request. | No |
| unauthenticated | No x-loop-key header, an unknown key, a revoked key, or a prefix that does not match the stored kind. | No |
| forbidden | A public key from an origin not on its allowlist, a secret key presented from a browser, or a secret key on an endpoint that only accepts a public one. | No |
| not_found | The thing addressed does not exist in the project behind your key. | No |
| conflict | The change collided with the current state. | No |
| payload_too_large | Past the ingest limits: 500 events per request, 32KB per event. | No |
| rate_limited | Past the key's daily quota. Back off; do not drop the event. | Yes |
| internal | Our fault. Nothing about your request needs changing. | Yes |
| overloaded | Also ours, and temporary. | Yes |
A non-retryable code will not become retryable by waiting.
A malformed batch stays malformed and a bad key stays bad, which is why the SDK drops those batches instead of retrying them. Retrying a 400 wastes the attempt and delays the events behind it.