Error codes
Every error of /api/v1 is {"error": {"code", "message", "details", "request_id"}}, and X-Request-Id is echoed on every response. The licence gate of a self-hosted server answers {"error": {"code", "message"}}.
| Status | Code | When |
|---|---|---|
| 400 | bad_request | a parameter that does not apply, e.g. queue for delayed jobs |
| 401 | mfa_challenge_invalid | |
| 401 | mfa_code_invalid | |
| 401 | mfa_required | right password, second factor needed; details.challenge |
| 401 | sdk_token_required | A valid Bearer JOOBQUI_SDK_TOKEN is required for /api/v1/sdk/*. |
| 401 | unauthenticated | |
| 402 | paid_license_required | An active paid self-hosted license is required. |
| 402 | pro_required | the call drives a JoobQ Pro feature — the workflow engine or workflow schedules — but this deployment has no valid Pro licence; Core keeps working, only the Pro-backed routes answer this; GET /capabilities reports features.pro: false so the console hides them |
| 402 | sso_upgrade_required | Single sign-on is not included in the current license tier. |
| 403 | env_token_admin | |
| 403 | forbidden | csrf for the missing header, origin for a cross-origin socket |
| 403 | forbidden_role | the role is too low for the route; the console disables those controls and, if one is still refused, toasts "You need the operator role for that" |
| 403 | invite_required | |
| 403 | mfa_enrolment_required | the account must set up a second factor first |
| 403 | mfa_needs_session | a token called /mfa |
| 403 | mfa_required_for_role | the role must keep its second factor |
| 403 | sign_up_closed | |
| 404 | not_found | including a step that is not in the workflow |
| 405 | method_not_allowed | Allow lists the methods; /stream without a WebSocket handshake: it is a WebSocket route only; a handshake from another origin gets Azu's plain 403, and a wrong version 426 with Sec-WebSocket-Version |
| 409 | conflict | a command that no longer applies: the run already finished, the step is not failed, the run cannot be re-driven; starting an id that belongs to another workflow; the last active admin; a token name that exists |
| 413 | payload_too_large | bodies are capped at limits.max_payload_bytes, 256 KiB |
| 422 | invalid_request | the message names the field |
| 429 | rate_limited | sign-in, sign-up, recovery, two-factor, single sign-on, run-now, channel test; always with Retry-After |
| 500 | internal_error | for anything unexpected (logged with the request id; no internals in the response). The single sign-on callback answers a refusal with a redirect to /ui/login?sso_error=…, not with this envelope. |
| 503 | sdk_token_not_configured | JOOBQUI_SDK_TOKEN is not configured on this self-hosted instance. |
| 503 | secrets_key_required | production without JOOBQUI_SECRETS_KEY: the second factor cannot be turned on |
| 503 | sessions_not_ended | a password was reset but the account's sessions could not be ended |
| 503 | unavailable | too many live connections, Redis or the audit log not answering, single sign-on's provider not answering |
The SDK gateway's batched calls answer per item: an item of POST /sdk/tasks/ack or POST /sdk/tasks/heartbeat that is refused carries error: {status, code, message} (not_found, lease_owner_mismatch, invalid_request) and the other items are settled.