Skip to content

Latest commit

 

History

History
213 lines (162 loc) · 8.63 KB

File metadata and controls

213 lines (162 loc) · 8.63 KB

Payment Gateway Errors — Taxonomy & Resolution Paths

When a payment attempt fails, Chargebee returns a structured error you can handle programmatically. This reference covers every error category, what causes it, and what to do about it.


Error response structure

All payment errors follow this shape:

{
  "api_error_code": "payment_processing_failed",
  "message": "The card was declined.",
  "error_code": 3000,
  "http_status_code": 400,
  "type": "payment",
  "payment_error_code": "card_declined"
}
Field Type Description
api_error_code string Machine-readable code. Use this for branching logic.
message string Human-readable description. Do not parse for logic — wording may change.
error_code integer Chargebee internal code. Reference only.
http_status_code integer HTTP status. Payment errors are always 400.
type string Error category. Payment errors are always "payment".
payment_error_code string Specific gateway reason code. See tables below.

Error categories

Payment errors fall into four categories. The right recovery path depends on the category.

Category What it means Recovery
Insufficient funds The card has no available balance Retry after funds available, or ask customer to use a different card
Card authentication 3DS or CVV verification failed Customer must re-authenticate or use a different card
Card restriction Card blocked for this transaction type Customer must contact their bank or use a different card
Gateway / network Temporary processing failure Retry with exponential backoff — usually resolves on its own

Insufficient funds errors

payment_error_code Meaning What to do
insufficient_funds Card balance too low for the charge amount Show customer a message to add funds or use a different card. Retry after 3–5 days.
withdrawal_count_limit_exceeded Customer's bank limits the number of daily transactions Retry the next day, or prompt for a different card.
credit_limit_exceeded Credit limit reached Prompt customer to use a different card. No retry benefit.

Recommended message to customer:

"Your payment didn't go through due to insufficient funds. Please add funds to your account or use a different payment method."


Card authentication errors

payment_error_code Meaning What to do
card_declined_3ds 3D Secure authentication failed Re-trigger the checkout flow so the customer can re-authenticate.
authentication_required Bank requires 3DS but it wasn't used Re-initiate payment with 3DS enabled.
invalid_cvv CVV doesn't match Ask customer to re-enter their card details. Do not retry with the same CVV.
card_expired Card expiration date has passed Ask customer to update payment method in your billing portal.
invalid_expiry_date Expiration date format is incorrect Validate expiry format client-side before submission.

3DS handling note: Chargebee's hosted pages handle 3DS automatically. If you use a custom integration, implement the 3DS flow before retrying.


Card restriction errors

These errors are set by the customer's bank and cannot be resolved by retrying.

payment_error_code Meaning What to do
card_declined Generic decline from the bank Prompt customer to contact their bank or use a different card.
do_not_honor Bank declined without a specific reason Same as card_declined. Banks often use this for fraud flags.
transaction_not_permitted Card is not enabled for this transaction type Customer must contact their bank to enable the transaction type or use a different card.
card_velocity_exceeded Too many transactions on this card in a short window Retry after 24 hours, or prompt for a different card.
fraudulent Bank flagged the transaction as potentially fraudulent Do not retry. Prompt customer to use a different card and contact their bank.
stolen_card Card reported stolen Do not retry. Flag this account for review.
lost_card Card reported lost Do not retry. Flag this account for review.
pickup_card Bank is requesting the card be retrieved (in-person only) Prompt customer to use a different card.

⚠️ Never retry fraudulent, stolen_card, or lost_card errors. Multiple retry attempts on flagged cards can trigger additional fraud signals and may violate your payment processor agreement.


Gateway and network errors

These are transient failures. A retry strategy usually resolves them.

payment_error_code Meaning What to do
processing_error Temporary gateway failure Retry with exponential backoff (see schedule below).
gateway_timeout Gateway didn't respond in time Retry after 30 seconds. If it persists, check your gateway status page.
insufficient_gateway_quota Rate limit hit on the gateway Reduce retry frequency. Chargebee's built-in dunning handles this automatically.
temporary_processing_failure Issuing bank is temporarily unavailable Retry after 1–2 hours.

Recommended retry schedule for transient errors:

Attempt Wait before retry
1st retry 30 seconds
2nd retry 5 minutes
3rd retry 1 hour
4th retry 24 hours
Give up Notify customer to update payment method

Chargebee's built-in dunning handles automated retries. Configure the schedule at Settings → Dunning. The custom retry logic above is only needed if you're managing payment collection yourself outside of Chargebee's dunning workflow.


Handling errors in code

Node.js

try {
  const result = await chargebee.subscription.create({
    plan_id: 'pro-monthly',
    customer_id: 'cus_KmQ9xT4pRw2v',
  }).request();
} catch (err) {
  if (err.type === 'payment') {
    handlePaymentError(err);
  } else if (err.type === 'invalid_request') {
    handleValidationError(err);
  } else {
    throw err; // unexpected error — surface it
  }
}

function handlePaymentError(err) {
  switch (err.payment_error_code) {
    case 'card_declined':
    case 'do_not_honor':
    case 'insufficient_funds':
      // Prompt customer to use a different card
      notifyCustomer('payment_failed_soft', err.message);
      break;

    case 'fraudulent':
    case 'stolen_card':
    case 'lost_card':
      // Do NOT retry — flag for review
      flagAccountForReview(err);
      break;

    case 'processing_error':
    case 'gateway_timeout':
    case 'temporary_processing_failure':
      // Transient — schedule a retry
      scheduleRetry();
      break;

    default:
      // Unknown payment error — log and notify customer
      logError(err);
      notifyCustomer('payment_failed_generic', err.message);
  }
}

Python

import chargebee

try:
    result = chargebee.Subscription.create({
        "plan_id": "pro-monthly",
        "customer_id": "cus_KmQ9xT4pRw2v",
    })
except chargebee.PaymentException as e:
    error_code = e.json_obj.get("payment_error_code")

    HARD_DECLINES = {"fraudulent", "stolen_card", "lost_card"}
    TRANSIENT_ERRORS = {"processing_error", "gateway_timeout", "temporary_processing_failure"}

    if error_code in HARD_DECLINES:
        flag_account_for_review(e)
    elif error_code in TRANSIENT_ERRORS:
        schedule_retry()
    else:
        notify_customer("payment_failed", str(e))

Customer-facing messages

Write error messages that tell the customer what happened and what to do next. Avoid exposing raw error codes.

Scenario Recommended message
Soft decline (funds, velocity) "Your payment couldn't be processed. Please try a different card or contact your bank."
Authentication failure "We couldn't verify your card. Please re-enter your details or use a different card."
Expired card "The card on file has expired. Please update your payment method."
Hard decline (fraud flag) "Your payment was declined. Please use a different card or contact your bank for details."
Transient / retry pending "We're having trouble processing your payment. We'll try again automatically — no action needed."

Related