Skip to content

Errors

Every error response has the same shape. Codes are stable strings you can branch on. Messages are for people and can change.

{
"error": {
"code": "invalid_request",
"message": "limit must be at most 200",
"details": [],
"request_id": "req_01JA8X4K3T9V2C7M5N6P8R0S1W"
}
}

Every response, successful or not, carries a Request-Id header. Include it when you contact support.

CodeHTTPMeaningWhat to do
invalid_request400A parameter or body failed validation. details lists the problems.Fix the request.
unauthorized401The key is missing, malformed, revoked or unknown.Check the Authorization header.
key_environment_mismatch401A test key was used against production, or the reverse.Use test keys with sandbox and live keys with production.
forbidden403The key lacks the scope, or the role cannot do this.Create a key with the needed scope.
not_found404The resource does not exist, or belongs to another organization.Check the id.
idempotency_conflict409The same idempotency key was reused with a different body.Use a new key, or resend the original body.
payload_too_large413The body is over 1 MB.Send smaller batches.
invalid_event422The event does not match the schema.See the event’s details.
invalid_signature422The event signature did not verify.Check the key and the canonical form.
pan_detected422A card number was found in the event.Remove it. HalvorAI never stores card numbers.
environment_mismatch422The event’s environment differs from the key’s.Send test events with test keys.
unknown_source422The event names a source that is not registered.Register the source first.
unprocessable422The request is valid but cannot be applied in the current state.Read the message.
rate_limited429Too many requests.Wait for the Retry-After seconds.
internal_error500Something failed on our side.Retry with backoff, and report the request_id if it persists.
unavailable503The service is temporarily unavailable.Retry with backoff.

POST /v1/events returns 202 for a batch even when some events are bad. Each event gets its own result, and a rejected one carries an error with the same codes, for example:

{ "id": "evt_01JA8Q...", "status": "rejected", "error": { "code": "invalid_signature", "message": "..." } }

Check every result, not just the HTTP status. See send events.

Retry 429, 500 and 503 with exponential backoff and jitter. Do not retry other 4xx codes unchanged: they will fail the same way. Sending an event again is safe, because the event id is its idempotency key.