Errors
Our API uses conventional HTTP response codes to indicate the success or failure of requests. Codes in the 2xx range indicate success, codes in the 4xx range indicate an error with the request, and codes in the 5xx range indicate an error with our servers.
HTTP Status Codes
2xx Success
- 200 OK - Request succeeded
- 201 Created - Resource created successfully
- 204 No Content - Request succeeded with no response body
4xx Client Errors
- 400 Bad Request - Invalid request parameters
- 401 Unauthorized - Invalid or missing API key
- 403 Forbidden - Insufficient permissions
- 404 Not Found - Resource doesn't exist
- 409 Conflict - Request conflicts with current state
- 422 Unprocessable Entity - Valid request but failed validation
- 429 Too Many Requests - Rate limit exceeded
5xx Server Errors
- 500 Internal Server Error - Something went wrong on our end
- 502 Bad Gateway - Temporary server error
- 503 Service Unavailable - Temporary server overload
Error Response Format
All errors return a consistent JSON structure:
{
"error": {
"code": "invalid_request",
"message": "Missing required parameter: email",
"param": "email",
"type": "invalid_request_error"
}
}
Error Object Fields
- code - Machine-readable error identifier
- message - Human-readable error description
- param - The parameter that caused the error (when applicable)
- type - The error category
Common Error Codes
Authentication Errors
authentication_required
{
"error": {
"code": "authentication_required",
"message": "No API key provided",
"type": "authentication_error"
}
}
invalid_api_key
{
"error": {
"code": "invalid_api_key",
"message": "Invalid API key provided: eyJhb...",
"type": "authentication_error"
}
}
Validation Errors
missing_parameter
{
"error": {
"code": "missing_parameter",
"message": "Missing required parameter: amount",
"param": "amount",
"type": "invalid_request_error"
}
}
invalid_parameter
{
"error": {
"code": "invalid_parameter",
"message": "Invalid currency: must be a valid ISO 4217 code",
"param": "currency",
"type": "invalid_request_error"
}
}
Resource Errors
resource_not_found
{
"error": {
"code": "resource_not_found",
"message": "No account found with id: acc_123",
"param": "id",
"type": "invalid_request_error"
}
}
insufficient_funds
{
"error": {
"code": "insufficient_funds",
"message": "The source account does not have sufficient funds",
"type": "card_error"
}
}
Rate Limiting
rate_limit_exceeded
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please wait before making another request",
"type": "rate_limit_error"
}
}
Error Handling Best Practices
1. Always check status codes
const response = await fetch('/v1/accounts', {
headers: { Authorization: `Bearer ${apiKey}` },
});
if (!response.ok) {
const error = await response.json();
throw new Error(`API Error: ${error.error.message}`);
}
const data = await response.json();
2. Handle specific error codes
try {
const account = await createAccount(data);
} catch (error) {
switch (error.code) {
case 'missing_parameter':
// Show validation error to user
break;
case 'authentication_required':
// Redirect to login
break;
case 'rate_limit_exceeded':
// Implement exponential backoff
break;
default:
// Log unexpected error
console.error('Unexpected error:', error);
}
}
3. Implement retry logic
async function makeRequest(url, options, retries = 3) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
// Rate limited - wait and retry
const retryAfter = response.headers.get('Retry-After') || '1';
await new Promise((resolve) =>
setTimeout(resolve, parseInt(retryAfter) * 1000)
);
if (retries > 0) {
return makeRequest(url, options, retries - 1);
}
}
if (response.status >= 500 && retries > 0) {
// Server error - exponential backoff
await new Promise((resolve) => setTimeout(resolve, (4 - retries) * 1000));
return makeRequest(url, options, retries - 1);
}
return response;
} catch (error) {
if (retries > 0) {
await new Promise((resolve) => setTimeout(resolve, 1000));
return makeRequest(url, options, retries - 1);
}
throw error;
}
}
4. Log errors properly
function logError(error, context) {
const logData = {
timestamp: new Date().toISOString(),
error_code: error.code,
error_message: error.message,
error_type: error.type,
context: context,
// Don't log sensitive data like API keys
};
console.error('API Error:', logData);
// Send to monitoring service
// analytics.track('api_error', logData);
}
Webhooks and Errors
When webhook delivery fails, we'll retry with exponential backoff:
- Immediate retry
- 1 minute later
- 5 minutes later
- 30 minutes later
- 2 hours later
- 6 hours later
After 6 failed attempts, we'll disable the webhook endpoint and send you a notification.
Testing Error Scenarios
Use these test values to simulate different error conditions:
Test API Key for Errors
eyJhb...error_400- Always returns 400 Bad RequesteyJhb...error_401- Always returns 401 UnauthorizedeyJhb...error_500- Always returns 500 Internal Server Error
Test Email Addresses
error@400.com- Returns 400 validation errorerror@404.com- Returns 404 not found errorerror@429.com- Returns 429 rate limit error
These test scenarios help you build robust error handling before going live.