Skip to main content
The Yativo Crypto API uses standard HTTP status codes and returns structured JSON error responses. All errors follow the same shape:
{
  "error": "error_code",
  "message": "Human-readable description of what went wrong",
  "details": { } // Optional: additional context
}

HTTP Status Codes

400 — Bad Request

The request was malformed or failed validation. Check the details field for which fields are invalid.
{
  "error": "validation_error",
  "message": "Request validation failed",
  "details": {
    "amount": "Must be a positive decimal number",
    "chain": "Unsupported chain identifier"
  }
}
How to handle: Fix the request before retrying. Do not retry 400 errors without modifying the request.

401 — Unauthorized

The request is missing authentication credentials, or the provided credentials are invalid or expired.
{
  "error": "unauthorized",
  "message": "Invalid or expired access token"
}
How to handle:
  • If using a Bearer token, refresh it via POST /apikey/token or GET /authentication/refresh-token
  • If using API key headers, verify your X-API-Key and X-API-Secret are correct

403 — Forbidden

The request is authenticated, but the API key or user does not have permission to perform the requested action.
{
  "error": "forbidden",
  "message": "API key does not have the 'transactions' permission"
}
How to handle: Check which permissions your API key has (GET /apikey/{id}). If needed, update permissions via PUT /apikey/{id}/permissions (requires 2FA).

404 — Not Found

The requested resource does not exist, or is not accessible from your account.
{
  "error": "not_found",
  "message": "Asset with ID 'asset_01xyz' not found"
}
How to handle: Verify the ID is correct. If you just created the resource, allow a moment for propagation and retry.

409 — Conflict

A duplicate operation was attempted. Most commonly seen with idempotency key conflicts.
{
  "error": "conflict",
  "message": "A transaction with this idempotency key already exists",
  "details": {
    "existing_transaction_id": "txn_01pqr456",
    "idempotency_key": "idem_7f3a9b2c1e4d"
  }
}
How to handle: If the details include an existing_transaction_id, that transaction is the canonical result — use it rather than creating a new one. This is the intended idempotency behavior.

422 — Unprocessable Entity

The request is syntactically valid but semantically invalid — for example, trying to send more than your wallet balance.
{
  "error": "insufficient_balance",
  "message": "Wallet balance (400.00 USDC) is less than the requested amount (1000.00 USDC)",
  "details": {
    "available_balance": "400.00",
    "requested_amount": "1000.00",
    "ticker": "USDC"
  }
}
Common 422 error codes:
Error CodeCause
insufficient_balanceWallet balance is too low for the requested transfer
invalid_addressThe to_address is not a valid address for the target chain
unsupported_tokenThe chain/ticker combination is not supported
quote_expiredA swap quote has passed its expires_at timestamp
gas_station_emptyThe gas station for this chain has no native tokens
card_not_activeThe target card is not in an active state
iban_not_activatedThe IBAN account has not completed activation
How to handle: Read the error_code and details to determine the specific issue. These errors require business logic changes (top up wallet, get a fresh quote, etc.) — not just a retry.

429 — Too Many Requests

Your request rate has exceeded the limit for your plan.
{
  "error": "rate_limit_exceeded",
  "message": "Too many requests. Please wait before retrying.",
  "retry_after": 12
}
How to handle: Wait retry_after seconds before retrying. Implement exponential backoff for sustained high-volume use. See Rate Limits for details.

500 — Internal Server Error

An unexpected error occurred on Yativo’s servers.
{
  "error": "internal_error",
  "message": "An unexpected error occurred. Please try again or contact support.",
  "request_id": "req_01abc123"
}
How to handle: Retry with exponential backoff. If the error persists, open a support ticket with the request_id value — it allows the Yativo team to trace the exact request in their logs.

Error Handling Pattern

async function callYativo(url: string, body: object): Promise<unknown> {
  const res = await fetch(url, {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${await getToken()}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify(body),
  });

  if (res.ok) return res.json();

  const error = await res.json();

  switch (res.status) {
    case 400:
      throw new ValidationError(error.message, error.details);
    case 401:
      await refreshToken();
      return callYativo(url, body); // retry once
    case 403:
      throw new PermissionError(error.message);
    case 404:
      throw new NotFoundError(error.message);
    case 409:
      // Idempotent — return the existing resource
      return error.details;
    case 422:
      throw new BusinessError(error.error, error.message, error.details);
    case 429:
      await sleep(error.retry_after * 1000);
      return callYativo(url, body);
    case 500:
      throw new ServerError(error.message, error.request_id);
    default:
      throw new Error(`Unexpected status ${res.status}: ${error.message}`);
  }
}

Idempotency

The POST /transactions/send-funds endpoint automatically generates a unique idempotency key for each request. If a network failure causes you to retry a send-funds call, you may receive a 409 Conflict response. This is not an error condition — it means the original transaction was already created. Use the existing_transaction_id from the 409 response body to track that transaction. To override the auto-generated key with your own, include "idempotency_key": "your-unique-key" in the request body. Keys must be unique per operation type.