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.

StatusMeansLeaves by
requires_payment_methodCreated, or a previous attempt was declinedConfirming with a payment method
requires_confirmationHas a payment method, not yet confirmedConfirm
requires_actionThe customer must do something, such as a 3D Secure challengeThe customer completing it
processingSubmitted; the outcome is not known yetAn event, possibly the next day
requires_captureAuthorised, waiting for you to captureCapture, or automatic cancellation after 7 days
succeededMoney collected— (terminal)
canceledAbandoned; no further charges— (terminal)
Payment intent statuses

Paths observed in the sandbox:

  • Card, approved: requires_payment_method → succeeded on confirm, with charge.succeeded and payment_intent.succeeded events.
  • Card, declined: requires_payment_method → confirm → requires_payment_method again, with the reason in last_payment_error. The status does not change; only the error does.
  • ACH debit: requires_payment_method → processing → succeeded about 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.

StatusMeans
pendingSubmitted and not yet settled — seen on ACH, with a charge.pending event
succeededThe attempt worked
failedThe attempt was declined; see failure_code
Charge statuses

Track the payment intent, not the charges. The charges are the history; the intent is the answer.

Refund

StatusMeans
pendingRequested, not yet complete
requires_actionSomething is needed before it can proceed
succeededThe money is on its way back
failedThe refund did not go through — the reference lists reasons such as expired_or_canceled_card
canceledWithdrawn before completion
Refund statuses

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

StatusMeansLeaves by
pendingCreated, waiting for the first payment at billing_cycle_anchorThe first payment
requires_confirmationNeeds confirming before it starts — used, for example, when a surcharge appliesPOST …/confirm
activeThe most recent payment succeededA failed payment, pause or cancellation
past_dueThe latest payment failed or was not attempted; next_payment_at becomes nullOnly your code updating the card and calling …/retry
pausedNo payments until resumed…/resume, or a resume_at date
canceledNo further payments— (terminal)
Subscription statuses

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

StatusMeans
pendingCreated, not yet sent to the bank
in_transitSubmitted to the bank
paidReported as delivered — but see below
failedRejected by the bank; see failure_code, such as account_closed or invalid_account_number
canceledWithdrawn
Payout statuses

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.

StatusStageYour move
warning_needs_responseInquiryRespond before it escalates
warning_under_reviewInquiryWait
warning_closedInquiryClosed without becoming a chargeback
needs_responseChargebackSubmit evidence before closing_at
under_reviewChargebackWait
wonResolvedFunds returned
lostResolvedFunds kept by the cardholder
closedResolvedClosed
Dispute statuses

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;
}
An explicit mapping from payment intent status to order state

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 own state. 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 paid and 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

ObjectStateWhy it gets missed
Payment intentrequires_actionNever happens in a test without 3D Secure; happens in production
Payment intentprocessingCards decide instantly, so it looks like an ACH-only edge case
Payment intentrequires_captureExpires after 7 days without warning
Payment intentrequires_payment_method after confirmLooks like "new" but means "declined"
Subscriptionpast_dueSits indefinitely with no automatic retry
RefundfailedRefunds feel like they cannot fail
Payoutpaid → failedpaid looks final and is not
Disputewarning_needs_responseAn inquiry, easy to ignore until it becomes a chargeback
Checklist of easily missed states

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.

Developers