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 StatusCodeWhen it happens
400VALIDATION_ERRORMissing or invalid request body fields, bad query parameters
401UNAUTHORIZEDMissing Authorization header, invalid key, revoked key, expired key, deactivated agent
402PAYMENT_REQUIREDPlan limit reached (e.g. monthly retrieval quota exceeded, max playbooks created)
403FORBIDDENValid credentials but insufficient role for this action (e.g. viewer trying to create)
404NOT_FOUNDResource doesn't exist, or you're not a member of the target workspace
409CONFLICTDuplicate resource (e.g. slug already exists in workspace)
422INVALID_STATE_TRANSITIONAction not allowed in current state (e.g. approving an already-approved version)
500INTERNAL_ERRORUnexpected 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.