Skip to main content

Documentation Index

Fetch the complete documentation index at: https://cryptorobot.ai/docs/llms.txt

Use this file to discover all available pages before exploring further.

Error Response Format

All errors follow a consistent JSON structure:
{
  "name": "BadRequest",
  "message": "Validation failed: 'pair' is required",
  "code": 400,
  "className": "bad-request",
  "errors": [
    {
      "field": "pair",
      "message": "'pair' is required"
    }
  ]
}
FieldTypeDescription
namestringError class name
messagestringHuman-readable description
codeintegerHTTP status code
classNamestringKebab-case error identifier
errorsarrayOptional: field-level validation errors

HTTP Status Codes

Success

CodeMeaningWhen
200OKGET, PATCH, DELETE succeeded
201CreatedPOST created a new resource

Client Errors

CodeNameMeaning
400BadRequestInvalid parameters or validation failure
401NotAuthenticatedMissing or invalid authentication
403ForbiddenAuthenticated but lacking permission
404NotFoundResource doesn’t exist
405MethodNotAllowedHTTP method not supported for this endpoint
408TimeoutRequest took too long
409ConflictResource already exists or state conflict
422UnprocessableRequest understood but semantically invalid
429TooManyRequestsRate limit exceeded

Server Errors

CodeNameMeaning
500GeneralErrorInternal server error
502BadGatewayUpstream service (exchange) unreachable
503UnavailableService temporarily unavailable

Common Error Scenarios

{
  "name": "NotAuthenticated",
  "message": "jwt expired",
  "code": 401,
  "className": "not-authenticated"
}
Fix: Re-authenticate with POST /authentication to get a fresh token.
{
  "name": "Forbidden",
  "message": "You do not have permission to access this resource",
  "code": 403,
  "className": "forbidden"
}
Fix: You can only access your own resources. Check the resource ID.
{
  "name": "BadRequest",
  "message": "Validation failed",
  "code": 400,
  "className": "bad-request",
  "errors": [
    {"field": "pair", "message": "'pair' is required"},
    {"field": "timeframe", "message": "must be one of: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w"}
  ]
}
Fix: Check the errors array for specific field issues.
{
  "name": "TooManyRequests",
  "message": "Rate limit exceeded. Try again in 30 seconds.",
  "code": 429,
  "className": "too-many-requests"
}
Fix: Implement exponential backoff. Check Retry-After header.

Rate Limits

Limits by Plan

PlanRequests/minBurstWebSocket connections
Free60101
Pro300505
Enterprise100010025

Rate Limit Headers

Every response includes rate limit information:
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 287
X-RateLimit-Reset: 1705316460
Retry-After: 30
HeaderDescription
X-RateLimit-LimitMax requests per window
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetUnix timestamp when the window resets
Retry-AfterSeconds to wait (only on 429 responses)

Endpoint-Specific Limits

Some endpoints have stricter limits:
EndpointLimitReason
POST /authentication10/minBrute-force protection
POST /auth-management5/minPassword reset abuse prevention
POST /strategies/backtest5/minCompute-intensive
POST /strategies/hyperopt3/minVery compute-intensive
POST /strategies/ai10/minAI generation cost

Handling Errors in Code

async function apiRequest(url, options) {
  const response = await fetch(url, options);

  if (!response.ok) {
    const error = await response.json();

    if (error.code === 401) {
      // Token expired — refresh and retry
      const newToken = await refreshAuth();
      options.headers['Authorization'] = `Bearer ${newToken}`;
      return fetch(url, options);
    }

    if (error.code === 429) {
      // Rate limited — wait and retry
      const retryAfter = response.headers.get('Retry-After') || 30;
      await new Promise(r => setTimeout(r, retryAfter * 1000));
      return fetch(url, options);
    }

    throw new Error(`${error.name}: ${error.message}`);
  }

  return response.json();
}

Retry Strategy

For production integrations, implement exponential backoff:
async function withRetry(fn, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    try {
      return await fn();
    } catch (error) {
      if (error.code === 429 || error.code >= 500) {
        const delay = Math.pow(2, i) * 1000 + Math.random() * 1000;
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      throw error; // Don't retry client errors (4xx except 429)
    }
  }
  throw new Error('Max retries exceeded');
}
Never retry 400, 403, or 404 errors — they won’t resolve by retrying. Only retry 429 (rate limit) and 5xx (server errors).