Skip to main content

Error Handling

The FYATU API uses conventional HTTP response codes and returns detailed error messages with machine-readable error codes to help you handle errors programmatically.

Response Format

All API responses follow a consistent format:
{
  "success": true,
  "status": 200,
  "message": "Operation completed successfully",
  "data": {
    // Response data here
  },
  "meta": {
    "requestId": "req_7af4d2b8e91c35fa",
    "timestamp": "2026-01-05T10:30:00+00:00"
  }
}
Always include the requestId from the meta object when contacting support — it helps us trace your request through our systems.

HTTP Status Codes

CodeStatusDescription
200OKRequest succeeded
201CreatedResource created successfully
400Bad RequestInvalid request parameters or validation failed
401UnauthorizedAuthentication failed or token expired
402Payment RequiredInsufficient wallet balance
403ForbiddenAccess denied (scope mismatch or resource not owned)
404Not FoundResource doesn’t exist
409ConflictDuplicate reference or conflicting operation
422Unprocessable EntityRequest understood but cannot be processed
429Too Many RequestsRate limit exceeded
500Server ErrorSomething went wrong on our end

Error Codes

Each error response includes a machine-readable code field:
CodeHTTPDescription
AUTH_TOKEN_MISSING401No authorization token provided
AUTH_TOKEN_INVALID401Token is malformed, expired, or revoked
AUTH_INVALID_CREDENTIALS401App ID or secret key is incorrect
AUTH_SCOPE_DENIED403Token doesn’t have the required scope for this endpoint
VALIDATION_ERROR400One or more request fields failed validation
RESOURCE_NOT_FOUND404The requested resource does not exist
INSUFFICIENT_BALANCE402Wallet balance is too low for this operation
DUPLICATE_REFERENCE409The externalReference has already been used
RATE_LIMIT_EXCEEDED429Too many requests — slow down
INTERNAL_ERROR500Unexpected server error

Common Error Scenarios

Authentication Errors (401)

Missing Token
{
  "success": false,
  "status": 401,
  "message": "Authorization token is required",
  "error": { "code": "AUTH_TOKEN_MISSING" }
}
Solution: Include the Authorization: Bearer {token} header in your request.
Expired Token
{
  "success": false,
  "status": 401,
  "message": "Invalid or expired token",
  "error": { "code": "AUTH_TOKEN_INVALID" }
}
Solution: Refresh your token via POST /v3/auth/refresh or request a new one via POST /v3/auth/token.
Insufficient Scope
{
  "success": false,
  "status": 403,
  "message": "Access denied. Required scope: cards:write",
  "error": { "code": "AUTH_SCOPE_DENIED" }
}
Solution: Your app type doesn’t have access to this endpoint. A Collection App cannot access Card endpoints and vice versa.

Validation Errors (400)

{
  "success": false,
  "status": 400,
  "message": "Validation failed",
  "error": {
    "code": "VALIDATION_ERROR",
    "details": [
      { "field": "amount", "message": "Amount must be greater than 0" },
      { "field": "email", "message": "The email field must contain a valid email address" }
    ]
  }
}
Solution: Check the details array for specific field requirements and fix the request payload.

Insufficient Balance (402)

{
  "success": false,
  "status": 402,
  "message": "Insufficient balance. Required: $105.00, Available: $50.00",
  "error": { "code": "INSUFFICIENT_BALANCE" }
}
Solution: Fund your business wallet before retrying. The required amount includes applicable fees.

Resource Not Found (404)

{
  "success": false,
  "status": 404,
  "message": "Card not found",
  "error": { "code": "RESOURCE_NOT_FOUND" }
}
Solution: Verify the resource ID exists and belongs to your app.

Duplicate Reference (409)

{
  "success": false,
  "status": 409,
  "message": "A collection with this external reference already exists",
  "error": { "code": "DUPLICATE_REFERENCE" }
}
Solution: Use a unique externalReference for each new operation.

Rate Limiting (429)

{
  "success": false,
  "status": 429,
  "message": "Rate limit exceeded. Try again in 60 seconds.",
  "error": { "code": "RATE_LIMIT_EXCEEDED" }
}
Solution: Implement exponential backoff in your retry logic.

Error Handling Best Practices

1. Always Check the Response

const response = await fetch('https://api.fyatu.com/api/v3/cards', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify(cardData)
});

const result = await response.json();

if (!result.success) {
  console.error(`API Error [${result.error?.code}]: ${result.message}`);
  console.error('Request ID:', result.meta?.requestId);
  return;
}

// Process successful response
console.log('Card created:', result.data.cardId);

2. Handle Specific Error Codes

async function createCollection(data) {
  const result = await fyatuRequest('POST', '/v3/collections', data);

  if (result.success) {
    return { ok: true, collection: result.data };
  }

  switch (result.error?.code) {
    case 'AUTH_TOKEN_INVALID':
      // Token expired — refresh and retry
      await refreshToken();
      return createCollection(data);

    case 'VALIDATION_ERROR':
      return { ok: false, fields: result.error.details };

    case 'INSUFFICIENT_BALANCE':
      return { ok: false, error: 'Please fund your wallet' };

    case 'DUPLICATE_REFERENCE':
      return { ok: false, error: 'This order was already submitted' };

    case 'RATE_LIMIT_EXCEEDED':
      await sleep(60000);
      return createCollection(data);

    default:
      return { ok: false, error: result.message };
  }
}

3. Implement Retry with Backoff

async function requestWithRetry(method, endpoint, data, maxRetries = 3) {
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    const result = await fyatuRequest(method, endpoint, data);

    if (result.success) return result;

    // Only retry on rate limits and server errors
    if (result.status === 429 || result.status >= 500) {
      const waitMs = Math.pow(2, attempt) * 1000;
      console.log(`Retry ${attempt}/${maxRetries} in ${waitMs}ms...`);
      await new Promise(r => setTimeout(r, waitMs));
      continue;
    }

    // Don't retry client errors (400, 401, 403, 404, 409)
    return result;
  }

  throw new Error(`Failed after ${maxRetries} retries`);
}

4. Log Errors for Debugging

function logApiError(endpoint, result) {
  console.error({
    timestamp: new Date().toISOString(),
    endpoint,
    status: result.status,
    code: result.error?.code,
    message: result.message,
    requestId: result.meta?.requestId,
    // Never log tokens, card numbers, or secrets
  });
}

Idempotency

For operations that create resources, use the externalReference field to prevent duplicates:
// Use a deterministic reference for each operation
const reference = `order_${orderId}_${customerId}`;

const result = await fyatuRequest('POST', '/v3/collections', {
  amount: 25.00,
  currency: 'USD',
  externalReference: reference,
  description: 'Premium subscription'
});

// If you retry with the same externalReference,
// the API returns 409 instead of creating a duplicate
This prevents duplicate charges if your request times out and you retry.

Rate Limits

Endpoint CategoryRate Limit
Authentication (/v3/auth/*)10 requests per minute
Read endpoints (GET)120 requests per minute
Write endpoints (POST/PUT/DELETE)60 requests per minute
Exceeding rate limits will result in 429 Too Many Requests. Implement exponential backoff in your retry logic.