Error Handling Guide
HTTP errors, payment failures, retry strategies, and debugging patterns
Exirom APIs return two distinct categories of errors: HTTP-level errors (transport/auth issues) and payment-level failures (declines, fraud). Each requires different handling.
#HTTP Status Codes
| Status | Meaning | How to Handle |
|---|---|---|
200 OK | Request succeeded — even failed payments return 200 | Check transactionStatus in the body |
400 Bad Request | Invalid or missing parameters | Fix payload: check required fields, data types, amount format |
401 Unauthorized | Missing or expired token | Re-authenticate via /api/v1/auth, then retry |
403 Forbidden | Valid token but insufficient permissions | Verify MID, contact Exirom support |
404 Not Found | Wrong endpoint path or unknown transactionId | Check URL and IDs against the API Reference |
409 Conflict | Duplicate requestId for a different request | Generate a new unique requestId |
422 Unprocessable | Structurally valid JSON but business rule violated | Review field constraints (e.g., amount precision, unsupported currency) |
429 Too Many Requests | Rate limit exceeded | Back off before retrying; reduce request rate |
500 Internal Server Error | Server-side error | Retry with exponential backoff; contact support if persistent |
503 Service Unavailable | Temporary outage | Retry after delay; check API status page |
Key rule: A
200response does not mean the payment succeeded. Always inspecttransactionStatus— a declined payment returns200withtransactionStatus: "FAILED".
#Payment-Level Failures
When transactionStatus is FAILED, check declineCode for the reason:
| Category | Examples | Action |
|---|---|---|
| Retry-eligible | Insufficient funds, temporary issuer unavailable | Prompt customer to retry or use another card |
| Fix required | Expired card, wrong CVV, invalid card number | Ask customer to update card details |
| Do not retry | Card blocked, fraud flagged, suspected fraud | Do not retry — show a generic error and offer alternatives |
| Contact support | Merchant configuration issues | Contact Exirom support |
See the Decline Codes Reference for the complete table with customer-friendly messages.
#Retry Strategy for HTTP Errors
For payment decline retry logic (which
declineCodevalues to retry, backoff schedules, idempotency), see Error Recovery Patterns.
#For HTTP 5xx errors (server-side)
Use exponential backoff with jitter:
async function withRetry(fn, maxAttempts = 4) {
let delay = 1000;
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
try {
return await fn();
} catch (err) {
if (attempt === maxAttempts || err.status < 500) throw err;
const jitter = Math.random() * 500;
await new Promise(r => setTimeout(r, delay + jitter));
delay *= 2; // 1s → 2s → 4s → 8s
}
}
}#For payment retries
Always use the same requestId when retrying a failed payment — this prevents double charges if the first attempt actually succeeded. Only generate a new requestId when starting a brand-new payment for a different order. See Idempotency for the full pattern.
#For HTTP 429 errors (rate limits)
Slow down and retry after a delay. If a Retry-After header is present, wait that long before retrying. If it is not present, wait at least 60 seconds and resume below the documented rate limit. For production traffic that needs higher throughput, contact your assigned account manager to whitelist your server IPs. See Going to Production for production limits and Sandbox Test Data for sandbox limits.
#Debugging Checklist
When a request fails unexpectedly:
- Log everything — status code, full response body,
traceId(in error responses),requestId - Check
transactionStatus— don't assume from HTTP status alone - Check the
declineCode— maps to a specific failure reason - Verify environment — sandbox tokens won't work in production and vice versa
- Validate your payload — amount format (string, not number), currency (ISO 4217), required fields
- Check token expiry — tokens expire after 30 days; a 401 often means a stale token
#Error Response Format
Most Exirom error responses (4xx/5xx) include a traceId for support escalation. Rate-limit responses (429) may be returned before the request reaches the API and may not include a JSON body or traceId.
{
"httpStatus": 401,
"internalCode": "auth-4003",
"errorMessage": "JWT token expiration error",
"traceId": "b1abae42b85ce937dcc1db984d5fcc7a",
"subErrors": []
}Always include the traceId when it is present. For rate-limit responses without a traceId, include the timestamp, endpoint, HTTP status, and your source IP.
#Related Guides
- Decline Codes Reference — every decline code, customer-facing message, and action
- Transaction Status Guide — full lifecycle and state transitions
- Error Recovery Patterns — retry strategies, idempotency, and fallback handling
- Common Mistakes — top integration pitfalls
- Troubleshooting — common issues and resolutions
- APM Error Handling — errors specific to alternative payment methods