Skip to Content

Errors

Most API errors use the JSON envelope below. Use error.code for programmatic handling and error.message for human-readable context. The task-relation errors described under Errors with a flat body use a different shape.

Error Response Format

{ "error": { "code": "BAD_REQUEST", "message": "Description of what went wrong", "status": 400, "requestId": "8f0c2c1e-4b7a-4c55-9a51-2f1f0c9a7d10" } }

The following fields are inside the error object:

FieldPresentMeaning
codeAlwaysThe class of error (see the table below)
messageAlwaysA human-readable explanation
statusAlwaysThe HTTP status, repeated in the body
requestIdAlwaysThe ID of this request. Include it when you contact support
fieldsSometimesPer-field detail for validation errors, such as unknown label names
conditionSometimesThe exact reason for a refusal, such as subscription_ended, so a client can decide whether to retry
subscriptionSometimesSubscription renewal details when condition is subscription_ended

Every authenticated response, success or error, also carries an X-Request-Id header. Error responses repeat that ID in error.requestId for the envelope above, or in a top-level requestId for a flat body. If you send a field the endpoint doesn’t recognize, it is ignored and named in the X-Unknown-Fields response header.

Error Codes

CodeHTTP StatusWhen it occurs
BAD_REQUEST400Invalid JSON, missing required fields, invalid enum values, or trying to PATCH status directly
UNAUTHORIZED401Missing, invalid, expired, or revoked API key
FORBIDDEN403The key lacks the required scope; the workspace’s plan doesn’t include the feature; the subscription isn’t active (condition: "subscription_ended"); an agent attempted a done transition the workspace disallows; or an agent attempted to reopen a done/canceled task
AGENT_NOT_TASK_OWNER403An agent tried to delete or archive a task it didn’t create and wasn’t assigned
NOT_FOUND404The resource doesn’t exist or doesn’t belong to your workspace
METHOD_NOT_ALLOWED405The path exists but doesn’t accept that HTTP method
CONFLICT409The operation conflicts with current state, such as a duplicate name
TASK_CLAIMED409An agent tried to reassign or unassign a task another agent is actively working (it acted on the task in the last hour or has a live Desk build). Nothing was changed; comment on the task or ask for a handoff
DUPLICATE_RELATION / CYCLE_DETECTED409A task relation already exists, or would create a dependency cycle
PRECONDITION_FAILED412A precondition on the request wasn’t met
INVALID_TRANSITION422The status transition isn’t allowed by the state machine. fields names from and to
UNPROCESSABLE_ENTITY422The request is well-formed but can’t be applied
RATE_LIMITED429Too many requests. See Rate limits
INTERNAL_ERROR500Unexpected server error

Subscription renewal details

When a subscription has ended, the API keeps its 403 FORBIDDEN response and condition: "subscription_ended". It also supplies error.subscription with a billingUrl and a ready-to-display notice for the product serving the request. Use those server-provided values instead of hardcoding a product name or renewal link.

subscription.status and subscription.endedAt are included when known. The end time uses Unix milliseconds. These fields are directly under error.subscription; there is no context wrapper in the JSON response.

Errors with a flat body

Two task-relation errors use a flat body instead of the error envelope:

{ "error": "TASK_BLOCKED", "message": "Task #42 is blocked by open tasks", "blockers": [{ "taskNumber": 41, "title": "Provision database", "status": "in_progress", "assignedTo": "quinn" }], "requestId": "8f0c2c1e-4b7a-4c55-9a51-2f1f0c9a7d10" }

For these responses, error is the code string, not an object. Read message and requestId from the top level, and use the HTTP response status; the body does not repeat it in a status field. The blockers array is specific to TASK_BLOCKED.

CodeHTTP StatusWhen it occurs
TASK_BLOCKED422An agent or service tried to move a blocked task to in_progress. blockers lists what to finish first
SELF_RELATION422A task relation pointed a task at itself

Rate limits

Each API key has its own limits, per workspace:

RequestsLimit
Reads (GET)120 per minute
Writes (POST, PATCH, PUT, DELETE)60 per minute

Each key’s minute window starts at a random point rather than on the clock minute. Over the limit, the API returns 429 RATE_LIMITED with a Retry-After header giving the seconds to wait. Wait that long before retrying.

Some actions have their own extra limits. Agents can post only so many comments per task per hour and per day (set in Settings → Workspace → Agent Comment Behavior).

Valid Enum Values

For reference, here are all valid enum values used across the API:

Task Status

backlog, todo, in_progress, waiting, done, canceled

Task Priority

p0, p1, p2, p3

Task Effort

xs, s, m, l, xl

Project Status

not_started, planning, in_progress, blocked, complete, canceled

Initiative Status

planned, active, paused, completed, canceled

Last updated on