StripeRunbook 0/4 done
insufficient_funds

Stripe Error insufficient_funds: Insufficient funds

Warning✕ Not retryable · fix the payloadHTTP 402 Payment RequiredAPI Gateway
TL;DR · 10-second read

The issuer declined because the account lacks available balance or credit. Show the customer a clear message and ask for another payment method; do not auto-retry the same card immediately.

Identify: does your log match?

What you see · exact log / response
{
  "error": {
    "charge": "ch_3QJ8xY2eZvKYlo2C0aBcDeFg",
    "code": "card_declined",
    "decline_code": "insufficient_funds",
    "doc_url": "https://stripe.com/docs/error-codes/card-declined",
    "message": "Your card has insufficient funds.",
    "payment_intent": { "id": "pi_3QJ8xY2eZvKYlo2C0hIjKlMn", "status": "requires_payment_method" },
    "type": "card_error"
  }
}
  1. High

    Customer balance or credit limit

    The debit balance or remaining credit line is lower than the amount. The issuer returns this specific decline_code.

  2. Medium

    Pending authorizations hold funds

    Earlier uncaptured authorizations (yours or other merchants') reduce available balance until they expire or are captured.

  3. Medium

    Off-session renewal on a drained card

    Subscription renewals charge without the customer present, so the decline is only seen in invoice.payment_failed.

Fix

Branch on decline_code and keep the PaymentIntent

✕ Broken · Node.js
try {
  await stripe.paymentIntents.confirm(piId);
} catch (err) {
  res.status(500).send('Payment failed');
}
✓ Fixed · Node.js
try {
  await stripe.paymentIntents.confirm(piId);
} catch (err) {
  if (err.type === 'StripeCardError') {
    const msg = err.decline_code === 'insufficient_funds'
      ? 'Your card has insufficient funds. Try another card.'
      : err.message;
    return res.status(402).json({ error: msg, paymentIntent: piId });
  }
  throw err;
}

Card errors are customer-actionable, not server faults. The PaymentIntent returns to requires_payment_method and can be confirmed again with a new card.

Verify: reproduce it on purpose

Reproduce locally · Stripe CLI
$ stripe payment_intents create --amount=2000 --currency=usd --payment-method=pm_card_visa_chargeDeclinedInsufficientFunds --confirm=true

Run it against a dev environment to trigger insufficient_funds on purpose and test your error handler.

Prevent

  • Show err.message for card_error; it is safe for customers.
  • Listen to invoice.payment_failed to email customers.
  • Never retry the same card in a tight loop; issuers flag it.

FAQ

How do I test insufficient_funds in test mode?

Use card 4000 0000 0000 9995 or the PaymentMethod pm_card_visa_chargeDeclinedInsufficientFunds. Both decline with decline_code insufficient_funds.

Is the code field insufficient_funds or card_declined?

code is card_declined and decline_code is insufficient_funds. Always read decline_code for the reason.

Does a decline cost a fee?

Stripe does not charge a processing fee for declined card payments in most regions. Excessive retries can still trigger issuer risk flags.

Related errors

Last verified 2026-10-21 · Source: Stripe OpenAPI spec + decline codes + webhook docs · Official docs ↗ · ~18,100 searches/mo