Error format

Every error has the same shape, whatever the route:
{
  "error": {
    "code": "insufficient_scope",
    "message": "this key does not have the deploy:write permission",
    "request_id": "7f3a2c91b0e44d8a9c1e5b2f60d3a847"
  }
}
FieldMeaning
codeA stable, machine-readable reason. Branch on this, not on the message
messageA short explanation for people
detailsPresent on some errors: the invalid fields, the allowed apps or workspaces, the rate-limit group
request_idThe id of this request, also sent as X-Request-Id. Quote it when you contact support
A request that fails validation answers 422 invalid_request with details listing each problem:
{
  "error": {
    "code": "invalid_request",
    "message": "the request is not valid",
    "details": [
      {"location": ["body", "goal"], "message": "Field required", "type": "missing"}
    ],
    "request_id": "2b81e0d4c6a94f17b3d8e5a0c9f2716b"
  }
}

Status codes

StatusCodes you may seeWhat to do
400bad_request, invalid_json, invalid_body, model_requiredFix the request
401invalid_keyCheck the key; create a new one if it was revoked or expired
402insufficient_creditsTop up the balance, or ask the person to
403insufficient_scope, key_spend_limit, ip_not_allowed, app_not_allowed, model_not_allowed, workspace_not_allowed, plan_required, account_unavailableChange the key’s permissions or limits, or the plan
404not_found, app_not_found, task_not_found, file_not_found, deployment_not_found, webhook_not_foundThe thing does not exist or this key cannot see it
409conflict, domain_taken, app_not_deployedThe current state does not allow it; read it and try again
413payload_too_largeSend a smaller body (see below)
422invalid_request, invalid_domain, invalid_urlFix the fields listed in details
429rate_limited, too_many_failed_attemptsWait for Retry-After seconds, then retry
500internal_errorRetry later; report the request_id if it persists
502, 503, 504upstream_error, upstream_unavailable, upstream_timeoutA Jobbit service is busy or restarting; retry with backoff

Rate limits

Limits are counted per person, so all of one person’s keys share them. They depend on the plan and on the kind of request:
GroupRoutesFreeGoPlus, Pro, Max
ReadGET routes120 / min300 / min600 / min
WriteChanges: deploy, env, DNS, webhooks, cancel20 / min60 / min120 / min
InferenceModel calls20 / min120 / min300 / min
Agent tasksCreating agent tasks5 / min20 / min60 / min
UploadsFile and project uploads5 / hour20 / hour60 / hour
Chat, embeddings and decision models also share a tokens-per-minute budget: 200,000 on Free and 2,000,000 on paid plans. GET /v1/plan shows the limits of your plan under api_limits. Every answer tells you where you stand:
HeaderMeaning
RateLimit-LimitRequests allowed in the window for this group
RateLimit-RemainingRequests left
RateLimit-ResetSeconds until the limit is full again
Retry-AfterOn 429 only: seconds to wait before retrying
A 429 from the token budget has "details": {"group": "tokens"}.

Request sizes

RouteLargest body
Most routes1 MB
Chat, audio and decisions25 MB (gzip accepted)
Automation packages20 MB
POST /v1/files100 MB

Retrying safely

  • Retry 429, 502, 503 and 504 with exponential backoff, and always honour Retry-After.
  • Do not retry 4xx errors other than 429 without changing the request.
  • Creating an agent task is safe to retry with an idempotency_key: the same key returns the same task instead of starting a second one.
  • Webhook deliveries can arrive more than once. Each event has a stable id, so ignore ids you have already handled.