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

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"



  © 2026 Taurus SA. All rights reserved.