Error Response Format
All API errors follow a consistent format:
{
"success": false,
"error": "Human-readable error message",
"details": [
{
"field": "amount",
"message": "Must be a positive number"
}
]
}HTTP Status Codes
| Code | Status | Description |
|---|---|---|
200 | OK | Request successful |
201 | Created | Resource created successfully |
400 | Bad Request | Invalid request data or validation error |
401 | Unauthorized | Missing or invalid authentication |
403 | Forbidden | Not authorized to access this resource |
404 | Not Found | Resource not found |
409 | Conflict | Resource already exists (e.g., duplicate txHash) |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Error | Server error - please contact support |
Common Errors
Validation Errors (400)
Invalid input dataRequest body doesn't match expected schema. Check the details array for specific field errors.
{
"success": false,
"error": "Invalid input data",
"details": [
{"path": ["amount"], "message": "Expected number, received string"},
{"path": ["token"], "message": "Invalid enum value. Expected 'USDC' | 'EURC'"}
]
}Invalid amountAmount must be between 0.01 and 1,000,000.
Invalid merchant addressThe toAddress doesn't match the merchant's wallet address.
Authentication Errors (401/403)
No token providedProtected endpoint requires authentication. Include Authorization or X-API-Key header.
Invalid or expired tokenJWT token has expired (15 min lifetime) or is malformed. Re-authenticate to get a new token.
Invalid API keyAPI key not found or has been revoked. Check that you're using the correct key.
Resource Errors (404/409)
Merchant not foundNo merchant exists with the given ID. Verify your merchantId.
Payment not foundNo payment exists with the given ID. Check the payment ID is correct.
Payment already existsA payment with this txHash already exists. This prevents double-spend attacks.
Rate Limiting
When you exceed rate limits, you'll receive a 429 response with additional headers:
HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1705312800
{
"success": false,
"error": "Too many requests",
"code": "RATE_LIMIT_EXCEEDED",
"retryAfter": 60
}Rate Limit Headers
| Header | Description |
|---|---|
Retry-After | Seconds to wait before retrying |
X-RateLimit-Limit | Maximum requests allowed in window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when limit resets |
Best Practice
Retry-After value and increase wait time for subsequent retries.CCTP Errors
Cross-chain payments can fail for several reasons:
| Error Code | Description | Resolution |
|---|---|---|
ATTESTATION_TIMEOUT | Circle attestation took too long | Automatic retry, usually resolves |
MINT_FAILED | Failed to mint on destination | Contact support with payment ID |
INSUFFICIENT_GAS | Backend wallet lacks gas | Internal issue, contact support |
INVALID_MESSAGE | CCTP message was invalid | Contact support with tx hash |
Failed CCTP payments store the error in the failure_reason field, accessible via the payment status API.
Fraud Detection
Fivo includes built-in fraud detection. These errors indicate potential attacks:
Payment amount verification failedThe claimed amount doesn't match the actual blockchain transaction amount. This could indicate an attempt to manipulate payment records.
Security
Error Handling Example
Here's how to properly handle API errors in your code:
async function createPayment(data) {
try {
const response = await fetch('https://api.fivo.finance/payments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': process.env.FIVO_API_KEY
},
body: JSON.stringify(data)
});
const result = await response.json();
if (!response.ok) {
// Handle specific error codes
switch (response.status) {
case 400:
console.error('Validation error:', result.details);
throw new Error('Invalid payment data');
case 401:
console.error('Authentication failed');
throw new Error('Please check your API key');
case 429:
const retryAfter = response.headers.get('Retry-After');
console.log(`Rate limited. Retry after ${retryAfter}s`);
throw new Error('Too many requests');
default:
throw new Error(result.error || 'Unknown error');
}
}
return result.data;
} catch (error) {
console.error('Payment failed:', error.message);
throw error;
}
}Still Having Issues?
If you encounter an error not listed here, please contact support with:
- The full error response
- Request details (endpoint, method, body)
- Payment ID or transaction hash (if applicable)
- Timestamp of when the error occurred