Error Handling
HTTP status codes, error response format, and common error codes
Error Handling
This guide covers the error response format and error codes used by the PRIME API.
Error Response Format
All errors return a JSON object with the following structure:
{
"code": 400,
"message": "Invalid quantity: must be positive",
"status": "INVALID_ARGUMENT",
"details": []
}Fields
| Field | Type | Description |
|---|---|---|
code | integer | HTTP status code |
message | string | Human-readable error description |
status | string | gRPC status code name |
details | array | Additional error context (optional) |
HTTP Status Codes
Client Errors (4xx)
| Code | Status | Description |
|---|---|---|
| 400 | INVALID_ARGUMENT | Request validation failed |
| 401 | UNAUTHENTICATED | Authentication required or failed |
| 403 | PERMISSION_DENIED | Authenticated but not authorized |
| 404 | NOT_FOUND | Resource does not exist |
| 409 | ALREADY_EXISTS | Resource already exists |
| 422 | FAILED_PRECONDITION | Business rule violation |
| 429 | RESOURCE_EXHAUSTED | Rate limit exceeded |
Server Errors (5xx)
| Code | Status | Description |
|---|---|---|
| 500 | INTERNAL | Unexpected server error |
| 503 | UNAVAILABLE | Service temporarily unavailable |
Error Reasons
The API uses specific reason codes to indicate the type of error.
Authentication & Authorization
| Reason | Description |
|---|---|
UNAUTHENTICATED | Missing or invalid authentication |
MFA_REQUIRED | Multi-factor authentication needed |
PERMISSION_DENIED | Insufficient permissions for operation |
ACCESS_REFUSED | Access explicitly denied |
ACCOUNT_IS_SUSPENDED | Account has been suspended |
Validation Errors
| Reason | Description |
|---|---|
INVALID_ARGUMENTS | Request parameters invalid |
INCORRECT_PARAMETER_VALUE | Specific parameter value invalid |
WEAK_PASSWORD | Password does not meet requirements |
USERNAME_ALREADY_EXISTS | Username is taken |
Resource Errors
| Reason | Description |
|---|---|
RESOURCE_NOT_FOUND | Requested resource does not exist |
ALREADY_EXISTS | Resource already exists |
CONSTRAINT_IN_PLACE | Operation blocked by constraint |
Trading Errors
| Reason | Description |
|---|---|
NOT_ENOUGH_FUNDS | Insufficient balance for operation |
CANNOT_RESOLVE_PRICE | Unable to determine execution price |
CLIP_SIZE_TOO_SMALL | Order quantity below minimum |
CLIP_SIZE_TOO_LARGE | Order quantity above maximum |
Deposit/Withdrawal Errors
| Reason | Description |
|---|---|
DEPOSIT_NOT_ENABLED | Deposits disabled for instrument |
DEPOSIT_ALREADY_IN_PROGRESS | Duplicate deposit detected |
DEPOSIT_ALREADY_CANCELED | Deposit was already cancelled |
DEPOSIT_CANNOT_BE_CANCELED | Deposit cannot be cancelled |
WITHDRAWAL_NOT_ENABLED | Withdrawals disabled for instrument |
System Errors
| Reason | Description |
|---|---|
INTERNAL | Internal server error |
UNAVAILABLE | Service temporarily unavailable |
SERVER_EXHAUSTED | Server resources exhausted |
CAPTCHA_FAILED | CAPTCHA verification failed |
Resource Names
Errors may include a resource name indicating which entity caused the error.
| Resource | Description |
|---|---|
USER | User account |
CLIENT_ACCOUNT | Client account entity |
SUBACCOUNT | Sub-account/portfolio |
INSTRUMENT | Tradable asset |
PAIR | Trading pair |
ORDER | Trading order |
TRADE | Executed trade |
BALANCE | Account balance |
DEPOSIT | Deposit transaction |
WITHDRAWAL | Withdrawal transaction |
TRANSFER | Internal transfer |
BANK_ACCOUNT | Bank account |
ADDRESS | Crypto address |
DOCUMENT | KYC document |
FEE | Fee calculation |
HOLDING | Asset holding |
LISTING | OTC listing |
EXPOSURE_LINE | Risk exposure |
Error Examples
Invalid Request
{
"code": 400,
"message": "quantity: must be greater than 0",
"status": "INVALID_ARGUMENT",
"details": []
}Authentication Failed
{
"code": 401,
"message": "JWT token was invalid",
"status": "UNAUTHENTICATED",
"details": []
}MFA Required
When MFA is enabled for a user but the TOTP code (challenge field) was not provided in the login request:
{
"code": 16,
"message": "MFA challenge required",
"details": [{
"@type": "type.googleapis.com/tgtraded.Error",
"reason": "MFA_REQUIRED"
}]
}To resolve, re-submit the login request with the challenge field containing the TOTP code.
Permission Denied
{
"code": 403,
"message": "User does not have trade permission on sub-account",
"status": "PERMISSION_DENIED",
"details": []
}Resource Not Found
{
"code": 404,
"message": "Order not found",
"status": "NOT_FOUND",
"details": [{
"resource": "ORDER",
"id": "order-uuid"
}]
}Insufficient Funds
{
"code": 403,
"message": "Insufficient CHF balance: required 50000.00, available 25000.00",
"status": "FAILED_PRECONDITION",
"details": [{
"reason": "NOT_ENOUGH_FUNDS",
"resource": "BALANCE",
"required": "50000.00",
"available": "25000.00"
}]
}Rate Limited
{
"code": 429,
"message": "Rate limit exceeded. Retry after 60 seconds",
"status": "RESOURCE_EXHAUSTED",
"details": [{
"reason": "SERVER_EXHAUSTED",
"retry_after": 60
}]
}Handling Errors
Best Practices
- Check HTTP status code first - Categorize by 4xx vs 5xx
- Parse the error response - Extract
messageanddetails - Handle specific reasons - Implement logic for expected errors
- Log unexpected errors - Include correlation ID for support
- Implement retries for 5xx - Use exponential backoff
Example Error Handler (JavaScript)
async function apiRequest(url, options) {
const response = await fetch(url, options);
if (!response.ok) {
const error = await response.json();
switch (error.status) {
case 'UNAUTHENTICATED':
// Refresh token or redirect to login
if (error.details?.some(d => d.reason === 'MFA_REQUIRED')) {
return handleMfaChallenge(error.details);
}
return redirectToLogin();
case 'PERMISSION_DENIED':
throw new Error('You do not have permission for this action');
case 'NOT_FOUND':
throw new Error('Resource not found');
case 'RESOURCE_EXHAUSTED':
// Implement retry with backoff
const retryAfter = error.details?.[0]?.retry_after || 60;
await sleep(retryAfter * 1000);
return apiRequest(url, options);
default:
throw new Error(error.message || 'An error occurred');
}
}
return response.json();
}Retry Strategy
For transient errors (5xx, rate limits):
async function withRetry(fn, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await fn();
} catch (error) {
if (attempt === maxRetries - 1) throw error;
if (error.status >= 500 || error.status === 429) {
const delay = Math.pow(2, attempt) * 1000; // Exponential backoff
await sleep(delay);
} else {
throw error; // Don't retry client errors
}
}
}
}Correlation ID
Every request is assigned a correlation ID for tracing. Include this ID when contacting support.
Finding the Correlation ID
- Check response headers:
X-Correlation-ID - Check error details: may include
correlation_idfield
Providing Your Own
You can provide a correlation ID in the request:
curl -X GET "https://api.t-dx.com/api/rest/v1/orders" \
-H "Authorization: Bearer <token>" \
-H "X-Correlation-ID: your-uuid-here"Updated 5 days ago
