Documentation Index
Fetch the complete documentation index at: https://docs.orsunpay.com/llms.txt
Use this file to discover all available pages before exploring further.
Error Codes and Handling
This guide provides comprehensive information about error handling in the Orsunpay API, including error codes, retry strategies, and best practices.
All API errors follow a consistent format:
{
"error": {
"code": "error_code",
"message": "Human-readable error description",
"details": {
"field": "Additional context about the error",
"suggestion": "Recommended action to resolve"
}
}
}
HTTP Status Codes
| Status | Name | Description | When to Retry |
|---|
400 | Bad Request | Invalid request parameters | ❌ Never |
401 | Unauthorized | Invalid or missing API key | ❌ Never |
403 | Forbidden | Insufficient permissions | ❌ Never |
404 | Not Found | Resource doesn’t exist | ❌ Never |
409 | Conflict | Resource conflict (e.g., duplicate) | ❌ Never |
422 | Unprocessable Entity | Valid request, business rule violation | ❌ Never |
429 | Too Many Requests | Rate limit exceeded | ✅ After delay |
500 | Internal Server Error | Server error | ✅ With backoff |
502 | Bad Gateway | Upstream service error | ✅ With backoff |
503 | Service Unavailable | Service temporarily down | ✅ With backoff |
504 | Gateway Timeout | Request timeout | ✅ With backoff |
Authentication Errors
authentication_required
{
"error": {
"code": "authentication_required",
"message": "No API key provided",
"details": {
"suggestion": "Include 'Authorization: Bearer your_api_key' header"
}
}
}
invalid_api_key
{
"error": {
"code": "invalid_api_key",
"message": "The provided API key is invalid",
"details": {
"suggestion": "Verify your API key is correct and active"
}
}
}
insufficient_permissions
{
"error": {
"code": "insufficient_permissions",
"message": "API key does not have permission for this operation",
"details": {
"required_permission": "transactions:write"
}
}
}
Validation Errors
invalid_request
{
"error": {
"code": "invalid_request",
"message": "Missing required parameter: amount",
"details": {
"field": "amount",
"location": "body"
}
}
}
invalid_parameter_value
{
"error": {
"code": "invalid_parameter_value",
"message": "Currency must be a valid ISO 4217 code",
"details": {
"field": "currency",
"provided": "US",
"expected": "USD"
}
}
}
parameter_out_of_range
{
"error": {
"code": "parameter_out_of_range",
"message": "Amount must be between 100 and 100000",
"details": {
"field": "amount",
"min": 100,
"max": 100000,
"provided": 50
}
}
}
Resource Errors
resource_not_found
{
"error": {
"code": "resource_not_found",
"message": "Transaction tr_invalid123 not found",
"details": {
"resource_type": "transaction",
"resource_id": "tr_invalid123"
}
}
}
resource_already_exists
{
"error": {
"code": "resource_already_exists",
"message": "Customer with buyerId 'customer_123' already exists",
"details": {
"field": "buyerId",
"existing_id": "cu_clkj3h2n0000qjr8x4c5h6e7b"
}
}
}
Business Logic Errors
transaction_not_capturable
{
"error": {
"code": "transaction_not_capturable",
"message": "Transaction must be in PROCESSING status to capture",
"details": {
"current_status": "SUCCESS",
"required_status": "PROCESSING"
}
}
}
insufficient_balance
{
"error": {
"code": "insufficient_balance",
"message": "Merchant account has insufficient balance for payout",
"details": {
"available_balance": 1000,
"requested_amount": 5000
}
}
}
payment_method_not_supported
{
"error": {
"code": "payment_method_not_supported",
"message": "Payment method 'crypto' not available in country 'BR'",
"details": {
"payment_method": "crypto",
"country": "BR",
"available_methods": ["card", "pix", "boleto"]
}
}
}
Rate Limiting Errors
rate_limit_exceeded
{
"error": {
"code": "rate_limit_exceeded",
"message": "Too many requests. Please retry after some time.",
"details": {
"limit": 1000,
"window": "1 hour",
"retry_after": 60
}
}
}
Provider Errors
provider_error
{
"error": {
"code": "provider_error",
"message": "Payment provider returned an error",
"details": {
"provider": "stripe",
"provider_code": "card_declined",
"provider_message": "Your card was declined"
}
}
}
provider_unavailable
{
"error": {
"code": "provider_unavailable",
"message": "Payment provider is temporarily unavailable",
"details": {
"provider": "paypal",
"estimated_recovery": "2023-11-15T11:00:00.000Z"
}
}
}
Idempotency Errors
idempotency_conflict
{
"error": {
"code": "idempotency_conflict",
"message": "Request conflicts with previous request using same idempotency key",
"details": {
"idempotency_key": "user_123_order_456",
"original_request_id": "req_abc123",
"conflict_field": "amount"
}
}
}
Retry Strategies
Exponential Backoff
async function retryWithBackoff(apiCall, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
return await apiCall();
} catch (error) {
// Don't retry client errors (4xx)
if (error.status >= 400 && error.status < 500) {
throw error;
}
// Don't retry on last attempt
if (attempt === maxRetries - 1) {
throw error;
}
// Exponential backoff: 1s, 2s, 4s
const delay = Math.pow(2, attempt) * 1000;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
}
// Usage
const transaction = await retryWithBackoff(async () => {
return await orsunpay.transactions.create(transactionData);
});
Rate Limit Handling
async function handleRateLimit(apiCall) {
try {
return await apiCall();
} catch (error) {
if (error.status === 429) {
const retryAfter = error.response?.headers?.['retry-after'] || 60;
console.log(`Rate limited. Retrying after ${retryAfter} seconds`);
await new Promise(resolve =>
setTimeout(resolve, retryAfter * 1000)
);
return await apiCall();
}
throw error;
}
}
Circuit Breaker Pattern
class CircuitBreaker {
constructor(threshold = 5, timeout = 60000) {
this.threshold = threshold;
this.timeout = timeout;
this.failures = 0;
this.state = 'CLOSED'; // CLOSED, OPEN, HALF_OPEN
this.nextAttempt = Date.now();
}
async call(apiCall) {
if (this.state === 'OPEN') {
if (Date.now() < this.nextAttempt) {
throw new Error('Circuit breaker is OPEN');
} else {
this.state = 'HALF_OPEN';
}
}
try {
const result = await apiCall();
this.onSuccess();
return result;
} catch (error) {
this.onFailure();
throw error;
}
}
onSuccess() {
this.failures = 0;
this.state = 'CLOSED';
}
onFailure() {
this.failures++;
if (this.failures >= this.threshold) {
this.state = 'OPEN';
this.nextAttempt = Date.now() + this.timeout;
}
}
}
// Usage
const breaker = new CircuitBreaker();
const transaction = await breaker.call(async () => {
return await orsunpay.transactions.create(transactionData);
});
Error Handling Best Practices
1. Implement Proper Error Handling
async function processPayment(paymentData) {
try {
const transaction = await orsunpay.transactions.create(paymentData);
return { success: true, transaction };
} catch (error) {
console.error('Payment processing error:', {
code: error.code,
message: error.message,
orderId: paymentData.orderId
});
// Handle specific error types
switch (error.code) {
case 'payment_method_not_supported':
return {
success: false,
error: 'This payment method is not available in your country',
suggestedMethods: error.details?.available_methods
};
case 'invalid_parameter_value':
return {
success: false,
error: `Invalid ${error.details?.field}: ${error.message}`
};
case 'rate_limit_exceeded':
// Implement retry logic or queue the request
return {
success: false,
error: 'Too many requests. Please try again in a few minutes.',
retryAfter: error.details?.retry_after
};
default:
return {
success: false,
error: 'Payment processing failed. Please try again.'
};
}
}
}
2. Log Errors Appropriately
function logError(error, context = {}) {
const logData = {
timestamp: new Date().toISOString(),
error_code: error.code,
error_message: error.message,
http_status: error.status,
request_id: error.request_id,
...context
};
// Don't log sensitive information
delete logData.api_key;
delete logData.customer_data;
console.error('API Error:', logData);
// Send to monitoring service
if (error.status >= 500) {
monitoring.alert('API Error', logData);
}
}
3. Graceful Degradation
async function getPaymentMethods(country, currency) {
try {
const methods = await orsunpay.paymentMethods.list({
country,
currency
});
return methods.data;
} catch (error) {
console.warn('Failed to fetch payment methods:', error.message);
// Fall back to default payment methods
return [
{ id: 'card', name: 'Credit/Debit Card' },
{ id: 'paypal', name: 'PayPal' }
];
}
}
4. User-Friendly Error Messages
function getUserFriendlyMessage(error) {
const messages = {
'authentication_required': 'Please log in to continue.',
'insufficient_permissions': 'You don\'t have permission to perform this action.',
'resource_not_found': 'The requested item could not be found.',
'rate_limit_exceeded': 'Too many requests. Please wait a moment and try again.',
'payment_method_not_supported': 'This payment method is not available.',
'provider_error': 'Payment processing failed. Please try a different payment method.',
'provider_unavailable': 'Payment service is temporarily unavailable. Please try again later.'
};
return messages[error.code] || 'An unexpected error occurred. Please try again.';
}
Monitoring and Alerting
Error Rate Monitoring
Set up alerts for:
- Error rate > 5% over 5 minutes
- Specific error codes (authentication, provider errors)
- Rate limiting events
- Circuit breaker state changes
Key Metrics
- Error Rate: Percentage of requests resulting in errors
- Error Distribution: Breakdown by error code and HTTP status
- Recovery Time: Time to recover from errors
- Retry Success Rate: Success rate of retry attempts
Always implement proper error handling and never expose sensitive information in error messages or logs.
Use idempotency keys for all state-changing operations to prevent duplicate processing in retry scenarios.