API error codes
What the Voidhash API, event capture and webhook verification helpers answer when they fail, and what to do.
Server-side errors carry a lower-case code, such as product_not_found, that the server libraries
expose unchanged: Node.js through getVoidhashApiError, PHP as ApiException::getErrorCode(), Go
as APIError.Code and Rust as Error::Api { code, .. }. Codes in UPPER_SNAKE_CASE come from the
client SDKs; see SDK error codes.
Management API
Every error has a type that matches the HTTP status and a specific code.
Errors shows the body, the types and the codes any operation can return;
Authentication lists why a credential is refused; each operation's
page in the API reference lists the codes it adds in its
Errors table. Payment source codes, such as payment_source_disabled, are under
Retries and corrections.
type | What to do |
|---|---|
invalid_request | Fix the request; param names the field. Don't retry unchanged. |
unauthenticated | Fix the credential. |
permission_denied | Give the key the access it needs. See Access levels. |
not_found | Check the ID, and that the key can use its project. |
conflict | Read the current state, then decide. |
rate_limited | Retry after the delay. |
internal | Retry safe requests with backoff. Contact support with the Request-Id header. |
unavailable | Retry later. |
SDK API
The endpoints the client SDKs call answer with a tagged error body instead. You see these only when you call the SDK API directly.
| Status | Tag | Meaning |
|---|---|---|
400 | Api/SdkValidationError | The request is invalid, such as a missing or malformed x-distinct-id. |
401 | Api/AuthenticationError | The publishable key was rejected. |
404 | Api/SdkPersonNotFoundError | Voidhash doesn't know the target person. |
409 | Api/SdkPersonAlreadyIdentifiedError | The anonymous ID already belongs to another identified person. |
422 | Api/SdkTransactionRejectedError | The store transaction can never be accepted as sent: the store isn't set up for this app, the ID is unknown, or the environment doesn't match. Don't retry. |
422 | Api/SdkPromotionalOfferUnavailableError | Voidhash won't sign this App Store promotional offer. Don't fall back to the regular price. |
424 | Api/PaymentSourceEndpointError | A payment source's endpoint failed or is missing. |
429 | Api/SdkRateLimitedError | Too many requests. Retry after Retry-After. |
500 | Api/SdkServiceError | Server failure. Retry with backoff. |
Event capture
/i/v1/capture and /i/v1/batch answer errors as { "error", "code" }. See
Retries for what to resend.
| Status | code | What to do |
|---|---|---|
400 | invalid_request | Fix the request. One invalid event rejects the whole batch. |
401 | unauthorized | Check the key and where you send it. |
413 | payload_too_large | Split the batch: at most 5 MB per body and about 250 KB per event. |
429 | rate_limited | Retry after retry_after_ms, with the same event UUIDs. |
500 | internal_error | Retry with backoff. |
503 | dependency_unavailable | Retry with backoff. |
Webhook verification
The library helpers that verify webhook signatures fail with a reason. Answer
400 for all of them.
| Reason | Libraries | Meaning |
|---|---|---|
missing_header | Node.js, PHP, Go | A signing header is missing, empty or sent more than once. |
timestamp_out_of_tolerance | Node.js, Go | The timestamp is malformed or more than 300 seconds from your clock. PHP reports this as invalid_signature. |
invalid_signature (Rust: InvalidSignature) | All | The signature doesn't match: wrong secret, or a modified or re-serialized body. |
invalid_payload (Rust: InvalidPayload) | All | The signature matches but the body isn't valid JSON. |
Next steps
Something wrong or missing on this page? Tell us by email or on Discord.