Error Handling
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 27 days ago
