When a payment fails, Dodo Payments tells you why through a standardized
error_code and a human-readable error_message. This guide shows how to read those fields, decide whether a retry is worthwhile, and recover the payment without exposing sensitive information to customers.How Dodo Payments Reports a Failure
Every failed payment — whether a one-time checkout or a subscription renewal — carries the same failure fields on the payment object:| Field | Type | Description |
|---|---|---|
status | string | failed for a failed payment. Other non-success states include cancelled, requires_customer_action, and requires_payment_method. |
error_code | string | null | The standardized failure reason, for example INSUFFICIENT_FUNDS or PROCESSING_ERROR. See the Transaction Failures reference for the full list. |
error_message | string | null | A human-readable explanation of the failure. |
retry_attempt | integer | 0 for the original charge. 1 or higher identifies a scheduled subscription renewal retry. |
error_code and error_message are null until a payment actually fails. Always check status first, then read the error fields.The payment.failed Webhook
The most reliable way to detect a failure is the payment.failed webhook. The event wraps the full payment object in data:
payment.failed payload
error_code and routes on it:
Decide Whether to Retry: Soft vs. Hard Declines
Theerror_code tells you whether retrying the same payment method is worthwhile.
| Decline type | What it means | What to do |
|---|---|---|
| Soft decline | Temporary or correctable (for example INSUFFICIENT_FUNDS, PROCESSING_ERROR, NETWORK_ERROR, TRY_AGAIN_LATER). | Retrying — after a delay, or once the customer fixes their input — can succeed. |
| Hard decline | Terminal (for example STOLEN_CARD, LOST_CARD, DO_NOT_HONOR, FRAUDULENT). | Do not retry the same card. Ask the customer for a different payment method. |
error_code.
Handling Failures at Checkout vs. on Renewal
How you recover depends on whether the customer is present.- At checkout (customer present)
- On subscription renewal (customer not present)
The customer is actively checking out. Surface a clear message and let them retry immediately or use another card.
requires_payment_method— the customer never provided a payment method: they didn’t enter card details, or were prompted for one and took no action. This is usually a checkout drop-off, not a decline — re-engage the customer to complete payment (see Abandoned Cart Recovery).requires_customer_action— additional authentication (such as 3DS) is needed; have the customer complete it. See 3D Secure handling.
Retrying a Failed Payment
- Subscriptions: Enable Subscription Payment Retries to recover soft declines with no integration work. You can also trigger recovery by having the customer update their payment method via the Update Payment Method API, which charges any outstanding dues.
- One-time payments: Resend the checkout or
payment_linkso the customer can try again with a different method. There is no automatic retry for one-time payments.
Surface Errors to Customers Safely
Show customers a friendly message — never the rawerror_code.
Customer-facing messaging
Related
Transaction Failures
Every decline code, its type, and the recommended action.
Error Codes
API and business-logic errors that are not card declines.
Subscription Payment Retries
Automatic recovery of soft declines on subscription renewals.
Subscription Dunning
Email sequences that recover hard declines.
Payment Webhooks
Full payload schema for payment events.
Testing Failures
Test cards that simulate declines and renewal failures.