Skip to content
Developer guide

Payment lifecycle

Status state machine for a transaction — every status, every valid transition, every webhook event that fires the change.

Context and key considerations

Every transaction moves through a small, deterministic state machine. There are SIX terminal-or-intermediate statuses and a fixed set of valid transitions. The status field on every transaction-shaped response (POST /payments, GET /payments/{id}, GET /payments) is one of these values — never anything else. Each transition fires a webhook event you can subscribe to.

1 / 5

Status values

StatusKindMeaning
pendingintermediateCreated. For async methods (SPEI, OXXO, voucher, bank_transfer, PIX) the customer hasn't paid yet — we're waiting for the upstream confirmation.
processingintermediateReserved status. The cascade marks pending on creation; we promote to processing if a provider explicitly signals partial-receipt (rare). Treat as equivalent to pending in client code.
completedintermediateMoney landed in your balance (after fees). For sync methods (card) this is the initial status. For async, this is the post-webhook transition. Stays intermediate because refund / chargeback can transition out of it.
failedterminalCharge failed and won't be retried. Either the cascade exhausted, the provider declined, or the customer abandoned a pending voucher/PIX before paying.
expiredterminalAsync-method-only. The customer didn't pay within the provider's window (SPEI typically 24h, voucher 7d). Functionally equivalent to failed for accounting — we keep it separate so dashboards can distinguish abandonment from explicit decline.
refundedterminalA completed transaction was refunded in full. Partial refunds also live here — check `amountRefunded` if you need to distinguish (future field).
chargebackterminalA completed transaction was disputed and the funds were released back to the cardholder. The dispute itself lives as a separate Claim record.
Key2Pay Developer documentationAPI v1
Documentation
Dashboard