Skip to content

Errors

All error responses follow a consistent format and include a machine-readable error code.

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Invalid email format",
"details": [
{ "field": "email", "message": "Must be a valid email address" }
]
},
"meta": {
"requestId": "req_abc123",
"timestamp": "2026-03-02T12:00:00Z"
}
}

The details array is optional and only present for validation errors, providing per-field error messages.

CodeHTTP StatusDescription
UNAUTHORIZED401Missing or invalid API key
FORBIDDEN403Valid key but insufficient scope for this endpoint
EMAIL_NOT_VERIFIED403Account email not verified — check inbox
NOT_FOUND404Resource does not exist or you don’t have access
VALIDATION_ERROR422Request body or parameters failed validation
RATE_LIMITED429Rate limit exceeded — see Retry-After header
CONFLICT409Duplicate resource or state conflict (e.g., slot already claimed)
PAYMENT_REQUIRED402Insufficient credit balance
IDEMPOTENCY_MISMATCH422Idempotency key reused with different request
INTERNAL_ERROR500Unexpected server error
SERVICE_UNAVAILABLE503Temporary outage — retry with backoff

Inspect the details array for field-specific messages:

{
"error": {
"code": "VALIDATION_ERROR",
"message": "Request validation failed",
"details": [
{ "field": "name", "message": "Required" },
{ "field": "tags", "message": "Must contain at least one tag" }
]
}
}

When rate limited, use the Retry-After header to determine when to retry:

HTTP/1.1 429 Too Many Requests
Retry-After: 30
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1709312400

Wait the specified number of seconds before retrying. See Rate Limiting for details on tiers and limits.

Returned when an operation conflicts with the current state:

{
"error": {
"code": "CONFLICT",
"message": "This playtest slot has already been claimed"
}
}

Common causes: slot already reserved by another playtester, duplicate resource creation, or state transition conflict.

Returned when a paid operation lacks sufficient credit:

{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Insufficient credit",
"details": [
{ "field": "balance", "message": "Current balance: $50.00, required: $100.00" }
]
}
}

Add credit via POST /api/v1/billing/credit before retrying.

Retry with exponential backoff. Include the requestId from the meta object when contacting support.

Every response includes a requestId in the meta object. Use this when reporting issues — it lets us trace the exact request through our logs.

{
"meta": {
"requestId": "req_abc123",
"timestamp": "2026-03-02T12:00:00Z"
}
}