Error Handling
API Errors
All Inflow API errors return a consistent JSON structure:
{
"statusCode": 400,
"message": "Validation failed",
"error": "Bad Request"
}HTTP Status Codes
| Code | Meaning | What to Do |
|---|---|---|
400 | Bad Request | Check your request body for missing or invalid fields |
401 | Unauthorized | Verify your API key is correct and included in the X-Inflow-Api-Key header |
404 | Not Found | The resource (payment, subscription, link) doesn't exist |
500 | Internal Server Error | Retry the request. If persistent, contact support |
Validation Errors
When request validation fails, the message field contains an array of error descriptions:
{
"statusCode": 400,
"message": [
"currency must be one of the following values: EUR, USD",
"products should not be empty",
"customerEmail must be an email"
],
"error": "Bad Request"
}Payment Error Codes
When a payment fails (e.g., card declined), the error details are available in the payment object's lastDepositAttempt.error field.
Where to Find Payment Errors
| Channel | How to Access |
|---|---|
| API | GET /api/payment/{id} → lastDepositAttempt.error field |
| Dashboard | Payment details page shows the error code and description |
| Webhooks | The payment_status_updated event payload includes the full payment object with error info |
| SDK | onComplete callback → result.error.message (customer-friendly message) |
Last Deposit Attempt Object
{
"lastDepositAttempt": {
"status": "failed",
"amount": 4999,
"paymentMethod": "CARD",
"error": "card_declined",
"attemptedAt": "2025-01-15T10:30:00.000Z"
}
}Common Payment Error Codes
| Error Code | Description | Customer Can Retry? |
|---|---|---|
card_declined | Card was declined by the issuing bank | Yes |
insufficient_funds | Not enough funds on the card | Yes |
expired_card | Card has expired | No |
incorrect_cvc | Wrong CVC/CVV code entered | Yes |
incorrect_number | Invalid card number | Yes |
invalid_cvc | CVC format is invalid | Yes |
invalid_expiry_month | Invalid expiration month | Yes |
invalid_expiry_year | Invalid expiration year | Yes |
invalid_number | Card number format is invalid | Yes |
processing_error | Temporary processing issue | Yes |
generic_decline | Declined without specific reason | Yes |
do_not_honor | Bank refused the transaction | Depends |
lost_card | Card reported as lost | No |
stolen_card | Card reported as stolen | No |
restricted_card | Card has restrictions | No |
authentication_required | 3DS authentication needed | Yes |
withdrawal_count_limit_exceeded | Transaction limit reached | Later |
SDK Error Handling (Customer-Facing)
The SDK's onComplete callback provides customer-friendly error messages:
onComplete: (result) => {
if (result.error) {
// result.error.message — Safe to display to the customer
// result.error.retryable — Whether the customer can try again
showError(result.error.message);
}
}These errors are designed for the end customer's checkout experience — they use clear, non-technical language.
Merchant Error Monitoring (API & Webhooks)
For merchant-side monitoring, use:
- API polling: Query
GET /api/payment/{id}and checklastDepositAttempt.error. - Webhooks: Listen for
payment_status_updatedevents — the payload includes the full payment object with error details. - Dashboard: The Payments page shows error codes for failed transactions.
Best Practices
- Always check the HTTP status code before parsing the response body.
- Handle 401 errors by verifying your API key configuration.
- For 500 errors, implement retry logic with exponential backoff.
- Monitor payment failures via webhooks rather than polling the API.
- Display SDK errors (
result.error.message) directly to customers — they are already user-friendly. - Log the raw error code (
lastDepositAttempt.error) for your internal monitoring.
Updated 1 day ago