Skip to main content
The Dakota API uses standard HTTP status codes and returns consistent error responses to help you handle errors programmatically.

HTTP Status Codes

Status CodeDescription
200Success - Request completed successfully
201Created - Resource created successfully
204No Content - Request succeeded with no response body
400Bad Request - Invalid request parameters or body
401Unauthorized - Missing or invalid API key
403Forbidden - Valid API key but insufficient permissions
404Not Found - Resource does not exist
409Conflict - Resource already exists or state conflict
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Server-side error
502Bad Gateway - Upstream service error
503Service Unavailable - Service temporarily unavailable

Error Response Format

All errors return a JSON structure with a code and message:
{
  "code": "error_code",
  "message": "Human-readable error description"
}

Error Codes

These error codes are returned by the Dakota API:
CodeDescription
unauthorizedAuthentication required or invalid API key
forbiddenInsufficient permissions
invalid_requestInvalid request parameters
invalid_identifierInvalid identifier format
customer_not_foundCustomer not found
recipient_not_foundRecipient not found
destination_not_foundDestination not found
account_not_foundAccount not found
transaction_not_foundTransaction not found
application_not_foundApplication not found
target_not_foundWebhook target not found
policy_not_foundPolicy not found
duplicate_identifierIdentifier already exists
duplicate_nameName already exists
limit_reachedResource limit reached
compliance_check_failedWallet address blocked due to compliance restrictions
bad_gatewayUpstream service error
service_unavailableService temporarily unavailable
internal_server_errorUnexpected server error
rate_limit_exceededToo many requests
application_not_readyApplication cannot be submitted - missing required information

Common Error Examples

Authentication Error (401)

{
  "code": "unauthorized",
  "message": "Unauthorized"
}
Common causes:
  • Missing x-api-key header
  • Invalid or expired API key

Validation Error (400)

{
  "code": "invalid_request",
  "message": "Bad Request"
}
Common causes:
  • Missing required fields
  • Invalid field format
  • Invalid enum values

Rate Limit Error (429)

{
  "code": "rate_limit_exceeded",
  "message": "Too many requests"
}
Rate limit headers are included in responses:
HeaderDescription
X-RateLimit-LimitMaximum requests allowed (60 for API key)
X-RateLimit-RemainRequests remaining in current window
X-RateLimit-ResetSeconds until window resets
See Rate Limiting for details.

Not Found Error (404)

{
  "code": "customer_not_found",
  "message": "Customer not found"
}

Duplicate Identifier Error (409)

{
  "code": "duplicate_identifier",
  "message": "Identifier already exists"
}

Limit Reached Error (429)

{
  "code": "limit_reached",
  "message": "Limit of API keys reached"
}

Compliance Error (403)

{
  "code": "compliance_check_failed",
  "message": "This wallet address cannot be processed due to compliance restrictions."
}

Bad Gateway Error (502)

{
  "code": "bad_gateway",
  "message": "Bad gateway"
}
Recommended action: Retry with exponential backoff.

Internal Server Error (500)

{
  "code": "internal_server_error",
  "message": "Internal Server Error"
}
Recommended action: Retry with exponential backoff. If the error persists, contact support.

Error Handling Best Practices

Basic Error Handler

const response = await fetch('https://api.platform.dakota.xyz/customers', {
  headers: { 'x-api-key': apiKey }
});

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

  switch (error.code) {
    case 'unauthorized':
      console.log('Check your API key');
      break;
    case 'rate_limit_exceeded':
      const resetSeconds = response.headers.get('X-RateLimit-Reset') || 60;
      await new Promise(r => setTimeout(r, resetSeconds * 1000));
      // Retry request
      break;
    case 'customer_not_found':
      console.log('Customer does not exist');
      break;
    default:
      console.error(`Error: ${error.message}`);
  }
}

Error Handler with Retry Logic

For transient errors (5xx, rate limits), implement exponential backoff:
async function fetchWithRetry(url, options, maxRetries = 3) {
  const retryableErrors = ['bad_gateway', 'service_unavailable', 'internal_server_error', 'rate_limit_exceeded'];

  for (let attempt = 0; attempt <= maxRetries; attempt++) {
    try {
      const response = await fetch(url, options);

      if (response.ok) {
        return response.json();
      }

      const error = await response.json();

      // Check if error is retryable
      if (retryableErrors.includes(error.code) && attempt < maxRetries) {
        let delay;

        if (error.code === 'rate_limit_exceeded') {
          // Use rate limit header if available
          delay = (parseInt(response.headers.get('X-RateLimit-Reset')) || 60) * 1000;
        } else {
          // Exponential backoff: 1s, 2s, 4s
          delay = Math.pow(2, attempt) * 1000;
        }

        console.log(`Retrying in ${delay}ms (attempt ${attempt + 1}/${maxRetries})`);
        await new Promise(r => setTimeout(r, delay));
        continue;
      }

      // Non-retryable error
      throw new Error(`API Error: ${error.code} - ${error.message}`);

    } catch (networkError) {
      // Network errors are retryable
      if (attempt < maxRetries) {
        const delay = Math.pow(2, attempt) * 1000;
        console.log(`Network error, retrying in ${delay}ms`);
        await new Promise(r => setTimeout(r, delay));
        continue;
      }
      throw networkError;
    }
  }
}

// Usage
try {
  const customer = await fetchWithRetry(
    'https://api.platform.dakota.xyz/customers/123',
    { headers: { 'x-api-key': apiKey } }
  );
  console.log('Customer:', customer);
} catch (error) {
  console.error('Request failed after retries:', error.message);
}
import time
import requests
from typing import Optional, Dict, Any

def fetch_with_retry(
    url: str,
    headers: Dict[str, str],
    max_retries: int = 3
) -> Dict[str, Any]:
    """Make API request with exponential backoff retry logic."""

    retryable_errors = ['bad_gateway', 'service_unavailable', 'internal_server_error', 'rate_limit_exceeded']

    for attempt in range(max_retries + 1):
        try:
            response = requests.get(url, headers=headers)

            if response.ok:
                return response.json()

            error = response.json()
            error_code = error.get('code', '')

            # Check if error is retryable
            if error_code in retryable_errors and attempt < max_retries:
                if error_code == 'rate_limit_exceeded':
                    # Use rate limit header if available
                    delay = int(response.headers.get('X-RateLimit-Reset', 60))
                else:
                    # Exponential backoff: 1s, 2s, 4s
                    delay = (2 ** attempt)

                print(f"Retrying in {delay}s (attempt {attempt + 1}/{max_retries})")
                time.sleep(delay)
                continue

            # Non-retryable error
            raise Exception(f"API Error: {error_code} - {error.get('message', 'Unknown error')}")

        except requests.exceptions.RequestException as e:
            # Network errors are retryable
            if attempt < max_retries:
                delay = 2 ** attempt
                print(f"Network error, retrying in {delay}s")
                time.sleep(delay)
                continue
            raise

# Usage
try:
    customer = fetch_with_retry(
        'https://api.platform.dakota.xyz/customers/123',
        headers={'x-api-key': api_key}
    )
    print('Customer:', customer)
except Exception as e:
    print(f'Request failed after retries: {e}')

Idempotency

For POST requests, include x-idempotency-key header to safely retry failed requests:
const response = await fetch('https://api.platform.dakota.xyz/customers', {
  method: 'POST',
  headers: {
    'x-api-key': apiKey,
    'x-idempotency-key': 'unique-request-id',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(customerData)
});

Troubleshooting

For detailed troubleshooting, see our Troubleshooting Guide.