The first version of every payments integration has two states: paid and not paid. It works until the first bank payment sits in processing overnight, the first 3D Secure challenge leaves a payment in requires_action, or the first payout marked paid bounces three days later.
This is a reference to every status the Paydude API can report, taken from its specification, with the transitions we observed in the sandbox on 28 September 2026 marked as such.
Payment intent
The payment intent is the object your code creates and the one your order should follow.
| Status | Means | Leaves by |
|---|---|---|
requires_payment_method | Created, or a previous attempt was declined | Confirming with a payment method |
requires_confirmation | Has a payment method, not yet confirmed | Confirm |
requires_action | The customer must do something, such as a 3D Secure challenge | The customer completing it |
processing | Submitted; the outcome is not known yet | An event, possibly the next day |
requires_capture | Authorised, waiting for you to capture | Capture, or automatic cancellation after 7 days |
succeeded | Money collected | — (terminal) |
canceled | Abandoned; no further charges | — (terminal) |
Paths observed in the sandbox:
- Card, approved:
requires_payment_method→succeededon confirm, withcharge.succeededandpayment_intent.succeededevents. - Card, declined:
requires_payment_method→ confirm →requires_payment_methodagain, with the reason inlast_payment_error. The status does not change; only the error does. - ACH debit:
requires_payment_method→processing→succeededabout fourteen and a half hours later, delivered as an event.
Charge
A charge is one attempt at moving money. A payment intent can own several — every declined attempt leaves a failed charge behind, and a retry adds a new one to the same intent's charges list.
| Status | Means |
|---|---|
pending | Submitted and not yet settled — seen on ACH, with a charge.pending event |
succeeded | The attempt worked |
failed | The attempt was declined; see failure_code |
Track the payment intent, not the charges. The charges are the history; the intent is the answer.
Refund
| Status | Means |
|---|---|
pending | Requested, not yet complete |
requires_action | Something is needed before it can proceed |
succeeded | The money is on its way back |
failed | The refund did not go through — the reference lists reasons such as expired_or_canceled_card |
canceled | Withdrawn before completion |
The one to handle is failed. A customer whose card was closed after they paid cannot be refunded to that card, and an integration that marks the order refunded when it requests the refund will tell them the money is coming when it is not. Mark it refunded on success, and route failures to a person who can pay the customer another way.
Subscription
| Status | Means | Leaves by |
|---|---|---|
pending | Created, waiting for the first payment at billing_cycle_anchor | The first payment |
requires_confirmation | Needs confirming before it starts — used, for example, when a surcharge applies | POST …/confirm |
active | The most recent payment succeeded | A failed payment, pause or cancellation |
past_due | The latest payment failed or was not attempted; next_payment_at becomes null | Only your code updating the card and calling …/retry |
paused | No payments until resumed | …/resume, or a resume_at date |
canceled | No further payments | — (terminal) |
past_due is the one that costs money. It is not retried automatically: the subscription sits there until you act, and your app keeps granting access unless you decide otherwise. Handling failed payments in code covers the dunning loop it needs. And do not call /confirm on a pending subscription — pending is the healthy state, and confirm only applies to requires_confirmation.
Payout
| Status | Means |
|---|---|
pending | Created, not yet sent to the bank |
in_transit | Submitted to the bank |
paid | Reported as delivered — but see below |
failed | Rejected by the bank; see failure_code, such as account_closed or invalid_account_number |
canceled | Withdrawn |
Two more things the sandbox showed. A payout can carry a negative amount — a debit from the bank rather than a deposit. And one payout.created event arrived already reporting status: "paid", because the payout was created and paid in the same instant; the event name tells you what happened first, not the current state. Reconciling payouts with your database goes through a payout line by line.
Dispute
Disputes have the richest state machine, because an inquiry can precede a formal chargeback.
| Status | Stage | Your move |
|---|---|---|
warning_needs_response | Inquiry | Respond before it escalates |
warning_under_review | Inquiry | Wait |
warning_closed | Inquiry | Closed without becoming a chargeback |
needs_response | Chargeback | Submit evidence before closing_at |
under_review | Chargeback | Wait |
won | Resolved | Funds returned |
lost | Resolved | Funds kept by the cardholder |
closed | Resolved | Closed |
Evidence can only be submitted before closing_at; after it, the dispute closes with no response, which usually means losing it. That date is the one to alert on. The sandbox's testing guide shows inquiries moving from warning_needs_response to warning_under_review, and an inquiry that escalates continuing on to needs_response — so one dispute can pass through both halves of the table. What is a chargeback covers the process from the cardholder's side.
Modelling it in your own database
Two columns do most of the work. Keep the processor's status exactly as the API reports it, and keep your own business state — what the order means to you — separately, derived from it by an explicit table.
// Processor status -> what the order means to us. Every status the API can
// report appears here, so a new one fails loudly instead of falling through.
const ORDER_STATE = {
requires_payment_method: "awaiting_payment", // new, or declined — check last_payment_error
requires_confirmation: "awaiting_payment",
requires_action: "awaiting_customer", // 3D Secure: prompt, do not time out silently
processing: "pending", // ACH: do not fulfil yet
requires_capture: "authorised", // capture within 7 days
succeeded: "paid",
canceled: "canceled",
};
const TERMINAL = new Set(["paid", "canceled"]);
function nextOrderState(order, intent) {
const next = ORDER_STATE[intent.status];
if (next === undefined) throw new Error(`Unmapped intent status: ${intent.status}`);
if (TERMINAL.has(order.state)) return order.state; // never reopen a closed order
return next;
}Throwing on an unmapped status is deliberate. The day the API adds a status, you want an alert, not an order that silently falls into the wrong branch.
- Store the processor's status verbatim, as
processor_status, next to your ownstate. When they disagree, you can see why. - Keep a history table of every transition with its timestamp and the event that caused it. Disputes and support tickets arrive weeks later, and "what did we know when" is the question they ask.
- Terminal for the order is not terminal for the money. An order can be
paidand later partially refunded, disputed, or included in a payout that fails. Model those as separate records against the order, not as more order states.
The states you will forget, in one list
| Object | State | Why it gets missed |
|---|---|---|
| Payment intent | requires_action | Never happens in a test without 3D Secure; happens in production |
| Payment intent | processing | Cards decide instantly, so it looks like an ACH-only edge case |
| Payment intent | requires_capture | Expires after 7 days without warning |
| Payment intent | requires_payment_method after confirm | Looks like "new" but means "declined" |
| Subscription | past_due | Sits indefinitely with no automatic retry |
| Refund | failed | Refunds feel like they cannot fail |
| Payout | paid → failed | paid looks final and is not |
| Dispute | warning_needs_response | An inquiry, easy to ignore until it becomes a chargeback |
GOOD QUESTIONS
Frequently asked
What are the payment intent statuses?+
requires_payment_method, requires_confirmation, requires_action, processing, requires_capture, succeeded and canceled. Only succeeded and canceled are terminal. A declined payment returns to requires_payment_method with the reason in last_payment_error.
Can a paid payout fail?+
Yes. The API documents that some failed payouts initially show as paid and later change to failed, because a bank can return a transfer after accepting it. Keep handling payout.failed events for payouts you have already recorded as paid.
What does past_due mean on a subscription?+
The latest payment failed or was not attempted. The subscription is not retried automatically — it stays past_due until your code updates the payment method and calls the retry endpoint, or cancels it.
How long can a payment stay authorised before capture?+
Seven days. A payment intent left in requires_capture is canceled automatically exactly seven days after it was created.
Can a refund fail?+
Yes. A refund has its own status, and failed is one of them — for example when the original card has since been closed. Mark an order refunded when the refund succeeds, not when you request it.
How should I store payment status in my database?+
Keep the processor's status exactly as reported alongside your own order state, derive the order state through an explicit mapping that covers every status, and record each transition in a history table with the event that caused it.
