card_declinedhighAffects MRR

Stripe card_declined Error — Causes, Fix & MRR Impact

The Stripe card_declined error occurs when the card issuer declines the charge; the specific reason is in decline_code, causing failed payments and MRR risk for SaaS businesses processing subscription payments.

What this means

The card was declined. The exact reason is in the decline_code (e.g. insufficient funds, expired card). Use that to decide retry vs update card vs generic message.

Why it happens

Issuer decline (see decline_code)

The issuer declined for a reason returned in decline_code: insufficient funds, expired card, lost/stolen, etc.

Stripe Radar or block list

Stripe Radar or your block list may have blocked the payment; decline_code may be generic_decline or fraudulent.

Invalid card data

Incorrect number, expiry, or CVC can result in card_declined with codes like incorrect_number, invalid_expiry_month, invalid_cvc.

Authentication required

When 3DS is required and not completed, you may see authentication_required or card_declined depending on context.

MRR Impact

Card declines are a primary driver of involuntary churn. Handling by decline_code (retry, dunning, update) protects MRR.

Handling card_declined by decline_code is essential for MRR recovery in SaaS.

Avg. recovery rate: Varies by decline_code; overall recovery improves significantly with proper handling.

Urgency: within 24h

How to fix it

  1. 1

    Read decline_code from the error

    Access error.decline_code or payment_intent.last_payment_error.decline_code. Branch your logic on this value, not only on card_declined.

    const declineCode = err.decline_code || err.payment_intent?.last_payment_error?.decline_code;
  2. 2

    Map decline codes to actions

    Retry: insufficient_funds, do_not_honor, generic_decline, no_action_taken. Update card: expired_card, lost_card, stolen_card, card_not_supported. Show generic: fraudulent, restricted_card. No retry: duplicate_transaction (check for existing payment first).

  3. 3

    Implement retry with backoff for retriable codes

    Use Stripe's smart retry or your own schedule (e.g. 1, 3, 5 days). Use Idempotency-Key when retrying. Honor advice_code when present.

  4. 4

    Show customer-friendly messages

    Never show raw decline_code. Use a message per category (e.g. 'Your card was declined. Please try another card or update your payment method.'). For some codes, use generic only.

  5. 5

    Send dunning and offer payment update

    After first failure, send dunning email and in-app prompt to update payment method. Track recovery by decline_code to tune strategy.

Detect card_declined automatically

Monitor card_declined volume and recovery rate by decline_code; prioritize handling for top codes.

Monitor your Stripe health free →

FAQ

What is Stripe card_declined?
card_declined is a top-level error code when a card charge fails. The specific reason is in the decline_code (e.g. insufficient_funds, expired_card). For SaaS, always check decline_code to decide whether to retry, prompt for update, or show a generic message. Retries and dunning based on decline_code protect MRR.
How do I handle card_declined in code?
In your payment confirmation or webhook, read the error's decline_code. Map it to your logic: retry with backoff for soft declines (e.g. insufficient_funds), prompt for new card for hard declines (e.g. expired_card, lost_card). Never show raw codes to the customer; use friendly messages.
Should I retry card_declined?
It depends on decline_code. Retry with backoff for insufficient_funds, do_not_honor, generic_decline. Do not retry same card for expired_card, lost_card, stolen_card, card_not_supported. Use Stripe's advice_code when available.
Does card_declined affect MRR?
Yes. Card declines are a major cause of failed renewals. Handling by decline_code (retries, dunning, update flow) significantly improves MRR recovery.

Related errors