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

FieldTypeDescription
codeintegerHTTP status code
messagestringHuman-readable error description
statusstringgRPC status code name
detailsarrayAdditional error context (optional)

HTTP Status Codes

Client Errors (4xx)

CodeStatusDescription
400INVALID_ARGUMENTRequest validation failed
401UNAUTHENTICATEDAuthentication required or failed
403PERMISSION_DENIEDAuthenticated but not authorized
404NOT_FOUNDResource does not exist
409ALREADY_EXISTSResource already exists
422FAILED_PRECONDITIONBusiness rule violation
429RESOURCE_EXHAUSTEDRate limit exceeded

Server Errors (5xx)

CodeStatusDescription
500INTERNALUnexpected server error
503UNAVAILABLEService temporarily unavailable

Error Reasons

The API uses specific reason codes to indicate the type of error.

Authentication & Authorization

ReasonDescription
UNAUTHENTICATEDMissing or invalid authentication
MFA_REQUIREDMulti-factor authentication needed
PERMISSION_DENIEDInsufficient permissions for operation
ACCESS_REFUSEDAccess explicitly denied
ACCOUNT_IS_SUSPENDEDAccount has been suspended

Validation Errors

ReasonDescription
INVALID_ARGUMENTSRequest parameters invalid
INCORRECT_PARAMETER_VALUESpecific parameter value invalid
WEAK_PASSWORDPassword does not meet requirements
USERNAME_ALREADY_EXISTSUsername is taken

Resource Errors

ReasonDescription
RESOURCE_NOT_FOUNDRequested resource does not exist
ALREADY_EXISTSResource already exists
CONSTRAINT_IN_PLACEOperation blocked by constraint

Trading Errors

ReasonDescription
NOT_ENOUGH_FUNDSInsufficient balance for operation
CANNOT_RESOLVE_PRICEUnable to determine execution price
CLIP_SIZE_TOO_SMALLOrder quantity below minimum
CLIP_SIZE_TOO_LARGEOrder quantity above maximum

Deposit/Withdrawal Errors

ReasonDescription
DEPOSIT_NOT_ENABLEDDeposits disabled for instrument
DEPOSIT_ALREADY_IN_PROGRESSDuplicate deposit detected
DEPOSIT_ALREADY_CANCELEDDeposit was already cancelled
DEPOSIT_CANNOT_BE_CANCELEDDeposit cannot be cancelled
WITHDRAWAL_NOT_ENABLEDWithdrawals disabled for instrument

System Errors

ReasonDescription
INTERNALInternal server error
UNAVAILABLEService temporarily unavailable
SERVER_EXHAUSTEDServer resources exhausted
CAPTCHA_FAILEDCAPTCHA verification failed

Resource Names

Errors may include a resource name indicating which entity caused the error.

ResourceDescription
USERUser account
CLIENT_ACCOUNTClient account entity
SUBACCOUNTSub-account/portfolio
INSTRUMENTTradable asset
PAIRTrading pair
ORDERTrading order
TRADEExecuted trade
BALANCEAccount balance
DEPOSITDeposit transaction
WITHDRAWALWithdrawal transaction
TRANSFERInternal transfer
BANK_ACCOUNTBank account
ADDRESSCrypto address
DOCUMENTKYC document
FEEFee calculation
HOLDINGAsset holding
LISTINGOTC listing
EXPOSURE_LINERisk 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

  1. Check HTTP status code first - Categorize by 4xx vs 5xx
  2. Parse the error response - Extract message and details
  3. Handle specific reasons - Implement logic for expected errors
  4. Log unexpected errors - Include correlation ID for support
  5. 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

  1. Check response headers: X-Correlation-ID
  2. Check error details: may include correlation_id field

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"



  © 2025 Taurus SA. All rights reserved.