Skip to content

Payment Lifecycle

State diagram

┌──────────────────────────┐
│ requires_payment_method │◄── (created)
└─────────────┬────────────┘
│ payment method attached
┌──────────────────────────┐
│ requires_confirmation │
└─────────────┬────────────┘
│ confirm called
┌────────────┴─────────────────────┐
│ │
│ scheduled_payment_date │ no schedule / date = today
│ is in the future │
▼ ▼
┌──────────────┐ ┌──────────────────┴──────────────┐
│ ready │ │ │
│ (scheduled) │ ▼ ▼
└──────┬───────┘ ┌────────────────┐ ┌────────────────────────┐
│ │ processing │ │ requires_action │
process_at │ │ (PSP pending) │ │ (3DS challenge) │
reached │ └───────┬────────┘ └────────────┬───────────┘
│ │ │
▼ ┌──────┴──────┐ ┌──────┴──────┐
(joins processing ▼ ▼ ▼ ▼
flow above) ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐
│succeeded │ │ failed │ │succeeded │ │ failed │
└─────┬────┘ └──────────┘ └─────┬────┘ └──────────┘
│ full refund │ full refund
▼ ▼
┌──────────┐ ┌──────────┐
│ refunded │ │ refunded │
└──────────┘ └──────────┘
Any non-terminal state → canceled (terminal)

State descriptions

requires_payment_method

The initial state for all payment intents created via the API. No payment method has been attached. The intent stays here until a payment_method is provided at confirm time.

requires_confirmation

A payment method has been attached but confirm has not been called. In most flows this state is transient — you attach the payment method and call confirm in the same step.

ready

The payment intent has been confirmed with a future scheduled_payment_date. No money moves yet. The intent is queued — on the scheduled date, EnqueueScheduledPaymentIntentsJob picks it up and submits it for processing.

A ready intent can still be canceled before its scheduled date.

See Scheduled Payments for details on creating scheduled intents.

requires_action

The payment requires an additional customer action, typically a 3D Secure authentication challenge. The widget handles this automatically. The intent transitions to processing after the action completes, or failed if the customer abandons the challenge.

processing

The payment has been submitted to the PSP and is awaiting a final result. This state can last from milliseconds to several business days depending on the payment method.

succeeded

The payment completed successfully. Terminal state — the customer has been charged. Partial refunds keep the intent in succeeded; only a full refund transitions to refunded.

refunded

All captured funds have been refunded. The intent transitions here automatically when the total refunded amount equals the original charge. Terminal state.

failed

The payment was declined or failed for another reason. Check the failure code for details. Terminal state — create a new payment intent to retry.

canceled

The payment intent was explicitly canceled. Terminal state.

What to build on

  • Use webhooks, not polling. The synchronous confirm response may show processing or ready — do not assume success until you receive payment_intent.succeeded.
  • succeeded is authoritative. Build your fulfillment logic on this webhook event.
  • failed is permanent. Create a new payment intent to retry a failed payment.
  • ready is not charged yet. A ready response means the payment is scheduled, not collected. Monitor payment_intent.succeeded to confirm funds were captured.

Refund states

After a payment intent reaches succeeded, refunds are tracked as separate objects. A partial refund keeps the payment intent in succeeded. A full refund (total refunded equals original charge) transitions the payment intent to refunded. Use the refund object’s status (succeeded, pending, failed) and the payment intent’s status to track state.