API error codes and how to handle them.
Error Codes
All API errors return a JSON body with an error field and optionally a code field and details object.
{
"error": "Human-readable error message",
"code": "MACHINE_READABLE_CODE",
"details": { }
}
Error codes
| Code | HTTP Status | Description | Action |
|---|---|---|---|
VALIDATION_ERROR | 400 | Request body failed schema validation | Check the details field for specific field errors |
UNAUTHORIZED | 401 | Missing or invalid API key | Verify your X-API-Key header |
FORBIDDEN | 403 | Valid key but insufficient permissions | Check that your key has access to the requested resource |
NOT_FOUND | 404 | Resource not found | Verify IDs (brand_id, etc.) are correct |
CONFLICT | 409 | Resource conflict (e.g., duplicate) | For events, this means the idempotency_key was already used |
RATE_LIMITED | 429 | Too many requests | Wait and retry. Check X-RateLimit-Remaining header |
INTERNAL_ERROR | 500 | Server error | Retry with exponential backoff. Contact support if persistent |
Handling errors in your integration
Retries: For 500 errors, implement exponential backoff (1s, 2s, 4s, 8s, max 60s). Include the same idempotency_key, as duplicate detection ensures safe retries.
Validation errors: The details field contains per-field errors:
{
"error": "Validation failed",
"code": "VALIDATION_ERROR",
"details": {
"fieldErrors": {
"currency": ["String must contain exactly 3 character(s)"],
"amount": ["Required"]
}
}
}
Rate limiting: If you receive a 429, pause sending and respect the rate limit window (1 minute). For high-volume integrations, use batch requests (100 events per request).