Error Handling
Structured errors with machine-readable codes.
Error format
Every error response returns a JSON object with a consistent structure. The code field is a stable, machine-readable string you can match on. The message is human-readable
and may change between releases.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "title is required.",
"details": {
"field": "title"
}
}
} The optional details field provides additional context for validation errors (e.g. which
field failed).
Error codes
| HTTP Status | Code | When it happens |
|---|---|---|
| 400 | VALIDATION_ERROR | Missing or invalid request body fields, bad query parameters |
| 401 | UNAUTHORIZED | Missing Authorization header, invalid key, revoked key, expired key, deactivated
agent |
| 402 | PAYMENT_REQUIRED | Plan limit reached (e.g. monthly retrieval quota exceeded, max playbooks created) |
| 403 | FORBIDDEN | Valid credentials but insufficient role for this action (e.g. viewer trying to create) |
| 404 | NOT_FOUND | Resource doesn't exist, or you're not a member of the target workspace |
| 409 | CONFLICT | Duplicate resource (e.g. slug already exists in workspace) |
| 422 | INVALID_STATE_TRANSITION | Action not allowed in current state (e.g. approving an already-approved version) |
| 500 | INTERNAL_ERROR | Unexpected server error — please report these |
Examples
Validation error
Returned when a required field is missing or a parameter value is invalid.
{
"error": {
"code": "VALIDATION_ERROR",
"message": "status must be one of: draft, approved, deprecated"
}
} Authentication error
Returned when the API key is missing, malformed, revoked, or expired.
{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or revoked API key."
}
} Payment required
Returned when you've hit a plan limit. The message field tells you which limit was exceeded.
Upgrade your plan or wait for the next billing period.
{
"error": {
"code": "PAYMENT_REQUIRED",
"message": "Upgrade required."
}
} Not found
Returned both when a resource genuinely doesn't exist and when you don't have access to it. This is intentional — the API avoids leaking whether a workspace or resource exists to non-members.
{
"error": {
"code": "NOT_FOUND",
"message": "Playbook not found."
}
} Handling errors in code
Match on the code field, not the message or HTTP status alone:
- VALIDATION_ERROR — check your request body and query params. Don't retry.
- UNAUTHORIZED — verify your API key is correct and not revoked. Check the authentication guide.
- PAYMENT_REQUIRED — check your workspace's current plan and usage. Upgrade or reduce usage.
- FORBIDDEN — the key is valid but the principal's role is too low. Use a key with a higher role or ask a workspace owner to upgrade the agent's role.
- NOT_FOUND — verify the workspace ID, resource ID, and that the principal is a member of the workspace.
- CONFLICT — the slug or unique constraint is taken. Use a different value.
- INVALID_STATE_TRANSITION — the resource isn't in the expected state. Fetch the current state before retrying.
- INTERNAL_ERROR — safe to retry with backoff. If it persists, contact [email protected].
Rate limits
The API does not currently enforce hard rate limits per key. However, retrieval endpoints (bundle
and manifest) are metered against your plan's monthly retrieval quota. When the quota is exceeded,
those endpoints return 402 PAYMENT_REQUIRED.