Errors
The Puck API uses standard HTTP status codes. Every error response — 4xx and 5xx — returns a JSON body so you can distinguish failure modes programmatically.
Error response shape
{ "error": "human-readable summary of what went wrong", "issues": [ { "path": "scope.filter.last_seen_within", "message": "must match pattern ^\\d+(s|m|h|d)$" } ]}error is always present. issues is present on 400 Bad Request responses where individual field validation failed; it is omitted on auth errors, rate-limit errors, and server errors.
Status codes
| Code | Meaning | When you see it |
|---|---|---|
200 OK | Success with body | GET, DELETE (cancellation), PATCH |
201 Created | Resource created | POST that created a persistent resource (subscriptions, inbound endpoints) |
202 Accepted | Queued asynchronously | Investigation trigger, test delivery, replay, inbound event receipt |
204 No Content | Success, no body | DELETE that hard-deletes a resource |
400 Bad Request | Validation failed | Missing required field, invalid enum value, constraint violation |
401 Unauthorized | Key missing or invalid | No Authorization header, revoked key, wrong key format |
403 Forbidden | Insufficient scope | Key is valid but lacks the required scope for this operation |
404 Not Found | Resource does not exist | Wrong ID, or ID belongs to a different account |
409 Conflict | Idempotency collision | Same Idempotency-Key sent with a different request body |
429 Too Many Requests | Rate limit exceeded | See Retry-After header for seconds until reset |
500 Internal Server Error | Server-side fault | Retry with exponential back-off; report to support if persistent |
501 Not Implemented | Endpoint reserved | Endpoint exists in spec but not yet deployed (e.g. GET /v1/graph/live) |
Common error codes
These are the most frequent error strings you will see in the error field:
error string | Cause |
|---|---|
missing_required_field | A required body field was omitted |
validation_error | One or more fields failed format or constraint checks — see issues |
invalid_api_key | The key format is wrong or the key has been revoked |
insufficient_scope | Key lacks the required scope; the response body names the missing scope |
not_found | The requested resource does not exist in this account |
idempotency_conflict | An Idempotency-Key was reused with a different body |
rate_limit_exceeded | Too many requests in the current window |
investigation_not_active | Tried to cancel an investigation that is already terminal |
subscription_url_unreachable | Webhook subscription URL failed validation (test delivery) |
Retrying safely
429: Wait forRetry-Afterseconds then retry the identical request.500: Retry with exponential back-off starting at 1 second; cap at 60 seconds. Stop after 5 attempts and alert.400: Do not retry without fixing the request. Theissuesarray tells you what to fix.401/403: Do not retry — fix the key or its scopes first.409: Do not retry. Either your idempotency key was already used (fetch the original result) or you sent a different body (use a new key).
For asynchronous operations (investigation triggers, replays), 202 means the job is queued — the actual work may still fail later. Check the investigation status via GET /v1/investigations/{id} or listen for investigation.failed webhook events.