Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.fyatu.com/llms.txt

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

Error Handling

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

Response Format

All V3.20 responses follow a consistent structure:
{
  "success": true,
  "status": 200,
  "message": "Operation completed successfully",
  "data": { },
  "meta": {
    "requestId": "req_7af4d2b8e91c35fa",
    "timestamp": "2026-04-30T10:30:00+00:00"
  }
}
Always include the requestId from the meta object when contacting support — it lets 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
403ForbiddenToken lacks required scope for this endpoint
404Not FoundResource doesn’t exist or doesn’t belong to your business
409ConflictConflicting state (e.g., card already frozen)
422Unprocessable EntityRequest understood but cannot be processed
429Too Many RequestsRate limit exceeded
500Server ErrorUnexpected server error on our end

Error Codes

CodeHTTPDescription
AUTH_TOKEN_MISSING401No Authorization header provided
AUTH_TOKEN_INVALID401Token is malformed, expired, or revoked
AUTH_INVALID_CREDENTIALS401Business ID not found or secret key mismatch
AUTH_BUSINESS_INACTIVE401Business account is suspended or inactive
AUTH_SCOPE_DENIED403Token doesn’t have the required scope for this endpoint
AUTH_VERSION_MISMATCH401Token was issued for a different API version (e.g., V3 token on V3.20 endpoint)
VALIDATION_ERROR400One or more request fields failed validation
RESOURCE_NOT_FOUND404The requested resource does not exist or belongs to another business
INSUFFICIENT_BALANCE402Wallet balance is too low for this operation
PRODUCT_NOT_FOUND404The specified productId does not exist under your program
PRODUCT_INACTIVE422The card product is currently inactive
CARDHOLDER_INACTIVE422Cardholder is not active or KYC not verified
CARD_ALREADY_FROZEN409Cannot freeze an already-frozen card
CARD_NOT_FROZEN409Cannot unfreeze a card that is not frozen
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 Authorization: Bearer {token} header in every request.
Expired Token
{
  "success": false,
  "status": 401,
  "message": "Invalid or expired token",
  "error": { "code": "AUTH_TOKEN_INVALID" }
}
Solution: Refresh your token via POST /v3.20/auth/refresh or request a new one via POST /v3.20/auth/token.
Version Mismatch
{
  "success": false,
  "status": 401,
  "message": "Token version mismatch. This endpoint requires a V3.20 token.",
  "error": { "code": "AUTH_VERSION_MISMATCH" }
}
Solution: Generate a new token via POST /v3.20/auth/token using your businessId and secretKey. V3 app tokens are not accepted on V3.20 endpoints.

Scope Errors (403)

Insufficient Scope
{
  "success": false,
  "status": 403,
  "message": "Access denied. Required scope: cards:write",
  "error": { "code": "AUTH_SCOPE_DENIED" }
}
Solution: Request a new token that includes the required scope. You cannot add scopes to an existing token — issue a new one.

Validation Errors (400)

{
  "success": false,
  "status": 400,
  "message": "Validation failed",
  "error": {
    "code": "VALIDATION_ERROR",
    "details": [
      { "field": "productId", "message": "productId is required" },
      { "field": "amount", "message": "Amount must be greater than 0" }
    ]
  }
}
Solution: Check the details array for specific field requirements and correct 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 issuance fees.

Product Not Found (404)

{
  "success": false,
  "status": 404,
  "message": "Card product not found",
  "error": { "code": "PRODUCT_NOT_FOUND" }
}
Solution: Use GET /programs/{programId}/products to list your available products and verify the productId.

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

Check the Response Status

const response = await fetch('https://api.fyatu.com/api/v3.20/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(`[${result.error?.code}]: ${result.message}`);
  console.error('Request ID:', result.meta?.requestId);
  return;
}

console.log('Card created:', result.data.id);

Handle Specific Error Codes

async function createCard(data) {
  const result = await fyatuRequest('POST', '/v3.20/cards', data);

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

  switch (result.error?.code) {
    case 'AUTH_TOKEN_INVALID':
      await refreshToken();
      return createCard(data);

    case 'AUTH_SCOPE_DENIED':
      return { ok: false, error: 'Token lacks cards:write scope — re-authenticate with correct scopes' };

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

    case 'INSUFFICIENT_BALANCE':
      return { ok: false, error: 'Fund your wallet before issuing cards' };

    case 'PRODUCT_NOT_FOUND':
      return { ok: false, error: 'Invalid productId — use GET /programs/{id}/products to list valid products' };

    case 'CARDHOLDER_INACTIVE':
      return { ok: false, error: 'Cardholder KYC not verified' };

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

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

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;

    if (result.status === 429 || result.status >= 500) {
      const waitMs = Math.pow(2, attempt) * 1000;
      await new Promise(r => setTimeout(r, waitMs));
      continue;
    }

    return result;
  }

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

Rate Limits

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