All errors follow a consistent envelope:
{
"error": {
"code": "account_not_found",
"message": "Account not found.",
"requestId": "req_abc123"
}
}
| Field | Description |
|---|
code | Machine-readable error code. Use this for programmatic handling. |
message | Human-readable description. Intended for developers, not end users. Messages may change without notice. |
requestId | Unique request identifier. Include this when contacting support. |
HTTP status codes
| Status | Meaning |
|---|
400 | Bad request — invalid syntax, missing required fields, or validation failure. |
401 | Unauthorized — missing or invalid API key. |
403 | Forbidden — the API key is valid but lacks permission for this action. |
404 | Not found — the requested resource does not exist, or does not belong to your organization. |
409 | Conflict — the action conflicts with the resource’s current state (e.g., archiving an already-archived beneficiary, executing an expired quote). |
500 | Internal error — something went wrong on our end. Retry the request. |
502 | Upstream error — a dependent service failed (e.g., blockchain node). Retry the request. |
Error codes
Authentication
| Code | HTTP | Description |
|---|
missing_api_key | 401 | No Authorization header, or it doesn’t start with Bearer . |
invalid_api_key | 401 | The key doesn’t exist or has been revoked. |
authentication_failed | 401 | Key verification failed due to a server error. Retry. |
forbidden | 403 | API key is valid but not authorized for this action. |
Resource lookup
| Code | HTTP | Description |
|---|
not_found | 404 | Generic resource not found. |
organization_not_found | 404 | Organization does not exist. |
account_not_found | 404 | Account does not exist or does not belong to your organization. |
quote_not_found | 404 | Quote does not exist. |
beneficiary_not_found | 404 | Beneficiary does not exist or does not belong to the specified account. |
Business logic
| Code | HTTP | Description |
|---|
quote_expired | 409 | The quote has expired. Create a new one. |
quote_already_used | 409 | The quote has already been executed. |
beneficiary_already_archived | 409 | The beneficiary is already archived. |
insufficient_funds | 400 | The account does not have enough balance for this operation. |
Validation and system
| Code | HTTP | Description |
|---|
validation_error | 400 | Request body failed validation. Check the message for details. |
invalid_request | 400 | The request is malformed or contains invalid parameters. |
chain_send_failed | 502 | The on-chain transaction could not be submitted. |
internal_error | 500 | Unexpected server error. Retry the request. |
Handling errors
const response = await fetch('https://api.sandbox.nxos.io/v1/quotes', {
method: 'POST',
headers: {
'Authorization': 'Bearer nxos_sk_test_...',
'Content-Type': 'application/json',
},
body: JSON.stringify({ /* ... */ }),
});
if (!response.ok) {
const { error } = await response.json();
switch (error.code) {
case 'insufficient_funds':
// Handle insufficient balance
break;
case 'validation_error':
// Handle invalid input
break;
default:
// Log requestId for debugging
console.error(`API error: ${error.code} (${error.requestId})`);
}
}
Always include the requestId when reporting issues. It lets us trace the exact request through our systems.