Errors
Errors have one shape, and each code always has the same HTTP status:
{ "error": { "code": "INSUFFICIENT_SCOPE", "message": "This operation needs the assessments:write scope", "scope": "assessments:write" } }- Branch on
error.code, not onmessage, which is for people and can change. - Some codes add fields:
scope(INSUFFICIENT_SCOPE),reason(FORBIDDEN),entitlement,limit,used,plan(PLAN_LIMIT_REACHED),feature(PLAN_FEATURE_UNAVAILABLE). - Not found is always
404 NOT_FOUND: an unknown id, a malformed id and another organization’s id look the same. - A
401carriesWWW-Authenticate: Bearer realm="tradecraft", resource_metadata="https://api.tradecrafthub.ai/.well-known/oauth-protected-resource", witherror="invalid_token"when a token was sent. 500 INTERNALnever carries details. Quote the response’sX-Request-Idwhen you contact support.- New codes can be added for new situations. Treat an unknown code by its HTTP status.
The OAuth endpoints (/oauth/*, /.well-known/*) use the OAuth format instead: { "error": "invalid_client", "error_description": "…" } (RFC 6749).
Codes on API operations
Section titled “Codes on API operations”The reference lists these on the operations that can return them:
| Status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | The body, query or path is invalid. Also: an access token in the URL, a missing required Idempotency-Key, or a cursor from another organization or filter set. |
| 400 | ASSET_KIND_NOT_ALLOWED | The library does not accept this kind of document. |
| 401 | UNAUTHENTICATED | No valid credential: the token is missing, unknown, expired or revoked, or was issued for another resource (such as an MCP connection). |
| 402 | SPEND_CAP_EXCEEDED | The platform's monthly AI spend cap is reached. Operations that call AI models stop until it resets. |
| 402 | TENANT_AI_BUDGET_EXCEEDED | Your organization's monthly AI budget is used up. |
| 403 | FORBIDDEN | Authenticated, but the role, an object rule or a policy does not allow this. error.reason says why (for example member_inactive, permission_missing, not_opted_in, user_only, role). |
| 403 | PLAN_LIMIT_REACHED | A limit of your organization's plan is reached (error.entitlement, limit, used, plan). |
| 403 | PLAN_FEATURE_UNAVAILABLE | Your organization's plan does not include this feature (error.feature, plan). The API is on the Enterprise plan. |
| 403 | TRIAL_EXPIRED | The trial ended or the subscription was cancelled; the organization is read-only. |
| 403 | INSUFFICIENT_SCOPE | The token lacks the scope this operation needs. error.scope names it; WWW-Authenticate: Bearer error="insufficient_scope" too. |
| 403 | API_DISABLED | Your organization has not turned the API on (Admin → API → Settings). |
| 404 | NOT_FOUND | No such resource in your organization. Unknown ids, malformed ids and another organization's ids all answer this. |
| 409 | CONFLICT | The resource's state does not allow this now: wrong lifecycle state, a duplicate, or already running. |
| 409 | LIBRARY_ARCHIVED | The library is archived and read-only. |
| 409 | IDEMPOTENCY_CONFLICT | The Idempotency-Key was already used for a different request, or the first request with it is still running. |
| 429 | RATE_LIMITED | Too many requests. Wait for the number of seconds in Retry-After. |
The rest of the catalogue
Section titled “The rest of the catalogue”Tradecraft uses one catalogue across the product. These codes come from features that the API does not expose today, or from rare cases; most of them will not reach an API client, but handle them by status if they do:
| Status | Code | Meaning |
|---|---|---|
| 400 | WEAK_PASSWORD | Sign-in screens only: the password does not meet the policy. |
| 400 | INVALID_TOKEN | Sign-in screens only: the email link or invitation is invalid or already used. |
| 400 | EXPIRED_TOKEN | Sign-in screens only: the email link or invitation expired. |
| 400 | ASSET_SOURCE_NOT_ALLOWED | The library does not accept documents from this source. |
| 400 | MISSING_SCOPES | Integrations only: the pasted Confluence credential lacks required scopes (error.missing lists them). |
| 400 | CLASSIC_TOKEN | Integrations only: a classic (unscoped) Atlassian API token was pasted. |
| 400 | INVALID_CREDENTIAL | Integrations only: the provider rejected the pasted credential. |
| 400 | CLOUD_ID_UNRESOLVED | Integrations only: the Atlassian site could not be resolved. |
| 400 | SITE_NOT_FOUND | Integrations only: the Atlassian site address that was entered does not exist. |
| 401 | INVALID_CREDENTIALS | Sign-in screens only: wrong email or password. |
| 401 | INVALID_CODE | Sign-in screens only: wrong or expired authenticator code. |
| 403 | SSO_REQUIRED | Your organization requires single sign-on. |
| 409 | SLUG_TAKEN | Sign-up only: the organization address is taken. |
| 409 | LAST_ADMIN | The change would leave the organization without an active admin. |
| 409 | MANAGED_BY_IDP | The member is managed by your identity provider (SCIM or directory sync). |
| 409 | INTEGRATION_AUTH | The connected source needs to be reconnected. |
| 409 | INTEGRATION_NOT_CONNECTED | The source is not connected. |
| 409 | SITE_CHOICE_EXPIRED | Integrations only: the pending Atlassian site choice expired. |
| 410 | GONE | The resource existed but is gone for good. |
| 410 | ENDPOINT_REMOVED | The endpoint was removed. The message names its replacement. |
| 413 | PAYLOAD_TOO_LARGE | The upload is larger than allowed. |
| 415 | UNSUPPORTED_MEDIA_TYPE | The request's content type is not accepted. |
| 429 | LOCKED | Too many failed attempts. Locked until Retry-After. |
| 500 | INTERNAL | Unexpected server error. The body carries no details; quote the X-Request-Id when you contact support. |
| 502 | PROVIDER_ERROR | An upstream provider (an AI model, Confluence, an identity provider or a directory) failed. |
| 503 | SERVICE_UNAVAILABLE | A dependency is unavailable or not configured. |
| 503 | PLATFORM_NOT_CONFIGURED | The platform app for this source is not configured. |
Both tables are generated from the published OpenAPI description at build time.