Public API
Errors
Every error code the API returns, its HTTP status, what it means and what to do about it.
Errors use the standard envelope: an error object with a stable code and a readable message, and meta.request_id.
{
"error": {
"code": "SCOPE_MISSING",
"message": "This token is missing the organization:read scope."
},
"meta": { "request_id": "3a91d0c2-7b4e-4f8a-9c1d-5e2f6a7b8c90" }
}
Branch on error.code and the HTTP status. The message is written for people and may change.
Error codes
| Code | HTTP status | Meaning | What to do |
|---|---|---|---|
AUTH_INVALID | 401 | The token is missing, malformed, unknown, revoked or expired, or its owner can no longer hold it (for example the owner was deactivated). | Check the Authorization header and the token's status and owner in Settings > API. Do not retry with the same token. |
API_DISABLED | 403 | The API is switched off for this organization. | Ask an Executive to turn it on under Settings > API > Settings. |
PLAN_REQUIRED | 403 | The plan does not include API access, or the subscription is past due, suspended, cancelled or unpaid. | Resolve billing. API access is included in Pro, Business and Enterprise. |
IP_NOT_ALLOWED | 403 | The request came from an address outside the token's IP allowlist. | Call from an allowed address, or update the allowlist. |
SCOPE_MISSING | 403 | The token does not hold the scope this endpoint requires. The message names that scope. Also returned when a webhook subscription would deliver events whose read scope the token does not hold. | Add the scope to the token or its API role, if the owner's role allows it. |
FORBIDDEN | 403 | The token's owner is not allowed to do this in the app, even though the token holds the scope, for example approving their own request. Also returned when the client address cannot be determined. | Use a token whose owner has the authority in the app. |
MODULE_DISABLED | 403 | The module this endpoint belongs to (for example time tracking or expenses) is switched off for the organization. | An administrator can switch the module on in the app. |
NOT_FOUND | 404 | The resource does not exist, belongs to another organization, or the path is not an API endpoint. | Check the id and the path. |
METHOD_NOT_ALLOWED | 405 | The path exists but does not accept this HTTP method. The Allow header lists the methods it does accept. | Use a method from the Allow header. |
CONFLICT | 409 | The request conflicts with the resource's current state (for example an expense report that is no longer awaiting a decision, or a name that is already taken), or a request with the same idempotency key is still in progress. | Re-read the resource, or wait and retry. |
IDEMPOTENCY_CONFLICT | 409 | The Idempotency-Key was already used with a different request. | Use a new key for a different request. |
VALIDATION_FAILED | 422 | The body, a parameter, the cursor or a header is invalid. Malformed JSON and a body that is not application/json return this code. Also returned when the app's own rules refuse a write, for example insufficient balance or a locked date; the message then says why. details may name the field. | Fix the request. Retrying unchanged will fail again. |
RATE_LIMITED | 429 | A rate limit was exceeded, or the address is temporarily blocked after repeated failed authentication. | Wait for the number of seconds in Retry-After, then retry. See Rate Limits. |
INTERNAL | 500 | Something went wrong on our side. | Retry with backoff. If it persists, contact support with the request id. |
UNAVAILABLE | 503 | The API is temporarily unavailable. | Retry with backoff. |
Error bodies never include stack traces or internal details, and never list the token's scopes.
Which errors to retry
| Retry? | Codes |
|---|---|
Yes, after Retry-After | RATE_LIMITED |
| Yes, with exponential backoff | INTERNAL, UNAVAILABLE, and network errors or timeouts |
| After waiting briefly | CONFLICT caused by an in-progress idempotent request |
| No, fix the cause first | AUTH_INVALID, API_DISABLED, PLAN_REQUIRED, IP_NOT_ALLOWED, SCOPE_MISSING, FORBIDDEN, MODULE_DISABLED, NOT_FOUND, METHOD_NOT_ALLOWED, IDEMPOTENCY_CONFLICT, VALIDATION_FAILED |
When you retry a write, send the same Idempotency-Key so it cannot be applied twice. See Idempotency keys.
The network edge in front of the API can answer before your request reaches it:
413 for a request body over 1 MB, and 429 when an address sends too many requests. These responses may not use the JSON envelope. Treat any 429 the same way: wait, then retry.Requests & Responses
The response envelope, field naming, calendar dates and timestamps, cursor pagination, request bodies, idempotency keys and request ids.
Rate Limits
The request limits per token, per organization and per address, the RateLimit and Retry-After headers, the failed-authentication lockout, and how to back off.