Error Handling

API Errors

All Inflow API errors return a consistent JSON structure:

{
  "statusCode": 400,
  "message": "Validation failed",
  "error": "Bad Request"
}

HTTP Status Codes

CodeMeaningWhat to Do
400Bad RequestCheck your request body for missing or invalid fields
401UnauthorizedVerify your API key is correct and included in the X-Inflow-Api-Key header
404Not FoundThe resource (payment, subscription, link) doesn't exist
429Too Many RequestsYou hit a rate limit. Back off and retry
500Internal Server ErrorRetry 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"
}

Business Rule Errors

When a request is well-formed but refused by a business rule, the message field is an object carrying a stable errorCode you can branch on, a human-readable message, and optional details:

{
  "statusCode": 400,
  "timestamp": "2026-10-01T09:12:44.000Z",
  "path": "/api/server/payment",
  "correlationId": "req_abc123",
  "message": {
    "errorCode": "SAVED_PAYMENT_METHOD_ATTEMPT_LIMIT_EXCEEDED",
    "message": "This customer's saved payment method has already been charged 5 times in the last 30 days (successful and failed attempts included). Card network rules cap charges on a stored card; collect the card again through the SDK or Checkout for this payment.",
    "details": { "attempts": 5, "limit": 5, "windowDays": 30, "nextAllowedAt": "2026-10-18T14:03:10.000Z" }
  }
}
errorCodeMeaningWhat to Do
SAVED_PAYMENT_METHOD_ATTEMPT_LIMIT_EXCEEDEDThe customer's saved card has already been charged 5 times in the last 30 days (declines included). Nothing was charged.Do not retry with useCustomerPaymentMethod. Collect the card again through the SDK or Checkout. See Charge Limit Reached.

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

ChannelHow to Access
APIGET /api/payment/{id} → lastDepositAttempt.error field
DashboardPayment details page shows the error code and description
WebhooksThe payment.failed event payload includes the full payment object with error info
SDKonComplete 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 CodeDescriptionCustomer Can Retry?
card_declinedCard was declined by the issuing bankYes
insufficient_fundsNot enough funds on the cardYes
expired_cardCard has expiredNo
incorrect_cvcWrong CVC/CVV code enteredYes
incorrect_numberInvalid card numberYes
invalid_cvcCVC format is invalidYes
invalid_expiry_monthInvalid expiration monthYes
invalid_expiry_yearInvalid expiration yearYes
invalid_numberCard number format is invalidYes
processing_errorTemporary processing issueYes
generic_declineDeclined without specific reasonYes
do_not_honorBank refused the transactionDepends
lost_cardCard reported as lostNo
stolen_cardCard reported as stolenNo
restricted_cardCard has restrictionsNo
authentication_required3DS authentication neededYes
withdrawal_count_limit_exceededTransaction limit reachedLater

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:

  1. API polling: Query GET /api/payment/{id} and check lastDepositAttempt.error.
  2. Webhooks: Listen for payment.failed events — the payload includes the full payment object with error details (see event types).
  3. 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 429 errors, back off and retry — see Rate Limits.
  • 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.

Did this page help you?