Error codes
Errors follow problem+json (RFC 9457). Errors raised by the API gateway also carry the header X-Error-Source: gateway.
Error body
401
HTTP/1.1 401 Unauthorized
Content-Type: application/problem+json
X-Error-Source: gateway
{
"type": "https://nextx.vn/errors/unauthorized",
"title": "Please sign in to continue.",
"status": 401,
"traceId": "0HN7…",
"errorCode": "gateway.unauthorized",
"retryable": false
}errorCode is stable for machines; title is for people; retryable tells you whether a retry can succeed; include traceId when you contact support.
HTTP status codes
| HTTP | Meaning | How to fix |
|---|---|---|
400 oauth2.missing_client_id | client_id missing when requesting a token (likewise oauth2.missing_client_secret, oauth2.missing_workspace_id) | Send client_id, client_secret and workspace_id as form fields |
400 oauth2.unsupported_grant_type | Unsupported grant_type | Use grant_type=client_credentials |
401 oauth2.invalid_client | Wrong client_id / client_secret, or the client is not confidential | Check the key pair; contact NextX if the secret must be reissued |
401 oauth2.client_suspended | The app was suspended by NextX | Contact NextX support |
403 oauth2.app_not_installed | The workspace has not installed the app (no consent) — NOT a 404 | The workspace installs the app and grants the scopes under Connected apps |
403 oauth2.module_not_subscribed | No scope left after filtering by the modules the workspace pays for | Request scopes from modules the workspace has, or add the module |
401 gateway.unauthorized | Bearer token / API key missing, expired or invalid (problem+json, errorCode gateway.unauthorized) | Get a new token (TTL 3600s; the response has a refresh_token field, but it is empty) |
403 insufficient_scope | Only on ~25 routes in the gateway scope map: body { error: insufficient_scope, required: <scope> } | Request the scope in required + workspace consent |
403 Permission required: <scope> | Other routes are checked by the service: a missing scope returns 403 with detail "Permission required: <scope>" | Request the scope named in detail |
404 | Resource does not exist | Check the id / path |
429 | Rate limit exceeded (600 req/min per app by default) | Slow down and read the Retry-After header |
Missing permission (403)
Routes checked at the gateway return error: insufficient_scope with required (the scope needed). Routes checked by the module return detail like Permission required: <scope>.
403
{ "error": "insufficient_scope", "required": "crm.contacts.view" }When to retry
Retry only when retryable: true (429, 502, 503, 504), with increasing back-off. Send an Idempotency-Key on writes so a retry never creates a duplicate.