Errors and permissions
401 and 403 are not interchangeable, and a 409 is not a retry. Reading the status correctly cuts most investigations to one step.
Status → owner
Section titled “Status → owner”| Status | Who owns the fix | First check |
|---|---|---|
400 | The caller | A required field is missing — often portalID or the ticket id |
401 | Credential | Is the credential present, unexpired, and bound to this target? |
403 | Configuration | Does this identity have the role, the portal and the resource? |
404 | Either | Wrong path, or a resource outside the caller’s scope |
409 | State | A run or action already exists; wait or inspect, do not retry |
422 | The caller | The body parsed, but does not match the target’s schema |
429 | Capacity | A rate-limited mount; back off |
503 | Administrator | A scope or dependency could not be resolved |
Error codes by family
Section titled “Error codes by family”Webhook keys
Section titled “Webhook keys”| Code | Meaning |
|---|---|
WEBHOOK_API_KEY_REQUIRED | The route reached the handler without a resolved key policy |
WEBHOOK_API_KEY_INVALID | Key unknown or revoked |
WEBHOOK_TARGET_FORBIDDEN | Key exists but is not bound to this target or route |
WEBHOOK_MODEL_FORBIDDEN | Key is bound to a different model id |
WEBHOOK_WORKFLOW_FORBIDDEN | Key is bound to a different workflow |
WEBHOOK_EVENT_OVERRIDE_FORBIDDEN | The request tried to choose an event; the key decides it |
WEBHOOK_POLICY_NOT_ALLOWED | The profile behind the key is inactive or no longer authorised |
WEBHOOK_DELIVERY_PAYLOAD_MISMATCH | Idempotency-Key reused with a different body |
WEBHOOK_DELIVERY_KEY_MISMATCH | Idempotency-Key reused by a different key |
Sessions and roles
Section titled “Sessions and roles”| Code | Meaning |
|---|---|
MAIA_TOKEN_REQUIRED | No MAIA token on a protected surface |
MAIA_TOKEN_INVALID | Signature, expiry, or format rejected |
MAIA_SESSION_REVOKED | The token was validly signed but its session was revoked |
TECHNICIAN_ROLE_REQUIRED | The identity is not an SDP technician |
REQUESTER_ROLE_REQUIRED | The identity is not an SDP requester |
FORBIDDEN | Authenticated, but not permitted on this record |
FEATURE_DISABLED | The feature is switched off for this installation or portal |
Runs and approvals
Section titled “Runs and approvals”| Code | Meaning |
|---|---|
RUN_ALREADY_ACTIVE | One run per conversation at a time; wait for it to settle |
RUN_NOT_FOUND | Unknown run id, or one outside the caller’s scope |
ACTION_NOT_FOUND, ACTION_ID_REQUIRED | The approval id is missing or unknown |
ACTION_ALREADY_DECIDED | Someone already approved or rejected it |
APPROVAL_DECISION_REQUIRED | Neither approve nor reject was supplied |
APPROVAL_EXPIRED | The approval outlived its window; the run will not resume |
Knowledge and search
Section titled “Knowledge and search”| Code | Meaning |
|---|---|
SDP_SCOPE_UNAVAILABLE | The ticket-search portal scope could not be resolved |
CONVERSATION_NOT_FOUND | Unknown or out-of-scope conversation |
Two shapes, not one
Section titled “Two shapes, not one”The v1 routes answer with { "error": { "code": …, "message": … } }. A strict parser will still break on two families:
- legacy flow handlers — for example
/api/v1/rewriteMessageFromTechnician— can answer{ "error": "<string>" }; - a few internal admin handlers answer
{ "error": "Internal Server Error" }on an unexpected failure.
Branch on code when it exists, and treat a string error as an opaque message.
What a 403 is telling you
Section titled “What a 403 is telling you”A valid credential refused on a valid route means one of four things, in order of likelihood:
- Role — the account is not the type this surface serves.
- Portal — the record lives in another helpdesk; MAIA re-resolves the portal per request.
- Scope — the agent’s knowledge space or the tool’s access scope excludes this actor.
- Policy — an approval or automation policy forbids the operation outright.
Never work around a 403 by supplying a different portal identifier. The check exists because the caller asked for something it does not own.
Escalating safely
Section titled “Escalating safely”Send: timestamp with timezone, route, status, and the error code. Never send cookies, tokens, keys, full request bodies, or customer content. A code plus a route is enough to reproduce nearly everything on this page.
Related topics
Section titled “Related topics”Authentication · API reference · Troubleshooting: connections · Troubleshooting: permissions