Skip to main content
All errors follow a standard format to make error handling consistent and predictable.

Error Response Format

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error description"
  }
}

HTTP Status Codes

The API uses standard HTTP status codes to indicate the success or failure of requests.
Status CodeMeaning
200Success - Request completed successfully
400Bad Request - Invalid request parameters or body
401Unauthorized - Missing or invalid authentication
403Forbidden - Insufficient permissions
404Not Found - Resource not found
405Method Not Allowed - HTTP method not allowed
409Conflict - Resource conflict (e.g., duplicate)
415Unsupported Media Type - Invalid content type
422Unprocessable Entity - Request valid but cannot be processed
429Too Many Requests - Rate limit exceeded
500Internal Server Error - Server error
503Service Unavailable - Service temporarily unavailable
504Gateway Timeout - Gateway timeout

Error Codes

Authentication Errors

UNAUTHORIZED
401
Missing or invalid API key, or incorrect authentication method for the endpoint.
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or missing API key"
  }
}
FORBIDDEN
403
Valid authentication but insufficient permissions to access the resource.
{
  "error": {
    "code": "FORBIDDEN",
    "message": "Insufficient permissions to access this resource"
  }
}

Validation Errors

BAD_REQUEST
400
Request has invalid parameters, missing required fields, or malformed JSON.
{
  "error": {
    "code": "BAD_REQUEST",
    "message": "externalUserId is required"
  }
}
UNPROCESSABLE_ENTITY
422
Request is well-formed but cannot be processed due to business logic constraints.
{
  "error": {
    "code": "UNPROCESSABLE_ENTITY",
    "message": "KYC verification must be approved before creating holder"
  }
}

Resource Errors

NOT_FOUND
404
The requested resource does not exist.
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Holder with externalUserId 'user_123' not found"
  }
}
CONFLICT
409
Resource already exists or conflicts with another resource.
{
  "error": {
    "code": "CONFLICT",
    "message": "Holder with externalUserId 'user_123' already exists"
  }
}

Rate Limiting

TOO_MANY_REQUESTS
429
Too many requests sent in a given time period. Slow down and retry after the specified time.
{
  "error": {
    "code": "TOO_MANY_REQUESTS",
    "message": "Rate limit exceeded. Please try again in 60 seconds"
  }
}

Server Errors

INTERNAL_SERVER_ERROR
500
An unexpected error occurred on the server.
{
  "error": {
    "code": "INTERNAL_SERVER_ERROR",
    "message": "An unexpected error occurred"
  }
}
SERVICE_UNAVAILABLE
503
Service is temporarily unavailable, usually due to maintenance.
{
  "error": {
    "code": "SERVICE_UNAVAILABLE",
    "message": "Service temporarily unavailable"
  }
}

Error Handling Best Practices

Before parsing the response body, check the HTTP status code to determine if the request was successful.
const response = await fetch('https://api.karmapay.xyz/v0/end-users', {
  method: 'POST',
  headers: { 'Authorization': `Bearer ${API_KEY}` },
  body: JSON.stringify(data)
});

if (!response.ok) {
  const error = await response.json();
  console.error(`Error ${response.status}:`, error.error.message);
  return;
}

const result = await response.json();
For 5xx errors and rate limiting (429), implement exponential backoff retry logic.
async function fetchWithRetry(url, options, maxRetries = 3) {
  for (let i = 0; i < maxRetries; i++) {
    const response = await fetch(url, options);
    
    if (response.ok) {
      return await response.json();
    }
    
    if (response.status === 429 || response.status >= 500) {
      const delay = Math.pow(2, i) * 1000; // Exponential backoff
      await new Promise(resolve => setTimeout(resolve, delay));
      continue;
    }
    
    throw new Error(`Request failed: ${response.status}`);
  }
  
  throw new Error('Max retries exceeded');
}
Log error codes and messages to help with troubleshooting.
try {
  const result = await createHolder(userId);
} catch (error) {
  logger.error('Failed to create holder', {
    userId,
    errorCode: error.code,
    errorMessage: error.message,
    timestamp: new Date().toISOString()
  });
  
  // Handle error appropriately
}
Don’t expose raw error messages to end users. Translate technical errors into user-friendly messages.
const errorMessages = {
  'UNAUTHORIZED': 'Authentication failed. Please try again.',
  'NOT_FOUND': 'The requested resource was not found.',
  'TOO_MANY_REQUESTS': 'Too many requests. Please wait a moment and try again.'
};

function getUserFriendlyMessage(errorCode) {
  return errorMessages[errorCode] || 'An unexpected error occurred. Please contact support.';
}

Common Error Scenarios

Holder Not Found

This error occurs when trying to access a holder that doesn’t exist:
{
  "error": {
    "code": "NOT_FOUND",
    "message": "Holder with externalUserId 'user_123' not found"
  }
}
Solution: Ensure the holder exists before performing operations. Create the holder first using POST /v0/end-users.

Invalid API Key

This error occurs when the API key is missing, malformed, or invalid:
{
  "error": {
    "code": "UNAUTHORIZED",
    "message": "Invalid or missing API key"
  }
}
Solution:
  • Verify your API key is correctly set in the Authorization header
  • Ensure the key starts with karma_
  • Regenerate your API key if it may have been compromised

KYC Not Approved

This error occurs when trying to create resources for a user whose KYC is not yet approved:
{
  "error": {
    "code": "UNPROCESSABLE_ENTITY",
    "message": "KYC verification must be approved before creating virtual account"
  }
}
Solution: Wait for KYC approval before creating virtual accounts or liquidation addresses. Check KYC status using GET /v0/end-users/:externalUserId/kyc-links.

Need Help?

If you encounter persistent errors or need assistance: