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 Gym Master if the secret must be reissued |
401 oauth2.client_suspended | The app was suspended by Gym Master | Contact Gym Master 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 |
Call center API error codes
Branch on errorCode; title is the human-readable message.
| errorCode | HTTP | Meaning |
|---|---|---|
call.partner.agent_ref_required | 422 | Send exactly one of agentId / agentEmail / extension. |
call.agent.not_found | 404 | No such (active) agent in this workspace. |
call.partner.agent_not_allowed_for_key | 403 | The API key is restricted and may not act for this agent. |
call.agent.not_available | 409 | The agent is busy, paused or offline. |
call.partner.number_invalid | 422 | The phone number cannot be normalized to E.164. |
call.outbound.number_blocked | 409 | The number is on the do-not-call list. |
call.partner.caller_id_not_owned | 422 | callerId is not a number owned by the workspace. |
call.partner.transfer_target_required | 422 | Send exactly one transfer target. |
call.partner.call_not_active | 409 | The call has already ended. |
call.partner.recording_not_available | 404 | No recording for this call yet. |
call.esl.unavailable | 502 | The switch is temporarily unavailable — retry shortly. |
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": "gym.members.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.