THE INDEPENDENT PAYMENTS INTELLIGENCE PLATFORMBuilt around merchants. Not a single provider. ↗
Guide · Integration and engineering

Payment State Management

Provider A says: SUCCEEDED Provider B says: CAPTURED Provider C says: PAID Are those the same payment state? Sometimes. Not always. The words themselves are not enough. One provider may use succeeded to mean that a payment has been fully captured. Another may use paid for a metho

Research draft awaiting independent review. This material was adapted from an existing research library. Provider-specific promotions have been excluded automatically; facts, regulatory requirements, and conclusions must be verified before the page is indexed publicly.

Payment State Management: Designing a Reliable Payment State Machine

Provider A says:

SUCCEEDED

Provider B says:

CAPTURED

Provider C says:

PAID

Are those the same payment state?

Sometimes.

Not always.

The words themselves are not enough.

One provider may use succeeded to mean that a payment has been fully captured. Another may use paid for a method whose funds are confirmed but not yet represented the same way in settlement. Another may expose separate authorization and capture states. A bank-based payment may remain pending long after the customer has left the checkout.

This is why a merchant cannot safely define its payment architecture as:

merchant_payment.status = provider.status

A payment provider knows the state of its own transaction object.

The merchant needs something broader:

A durable model of what the payment currently means to the merchant, which financial operations have occurred, what remains possible, and how that conclusion was reached.

That is payment state management.

The goal is not to invent one universal status vocabulary.

It is to establish a merchant-owned state model that:

Gives business logic stable meanings

Preserves provider-native detail

Handles synchronous and asynchronous updates

Distinguishes uncertainty from failure

Rejects invalid state transitions

Keeps a history of what happened

Can be reconciled against provider and financial records

A good payment state machine normalizes what the merchant needs to know.

It does not pretend different payment providers or payment methods are identical.

Start with the merchant payment, not the PSP transaction

Before defining payment states, define what object is changing state.

A useful merchant model separates at least:

Order

The commercial obligation.

Example:

Order ORD-1842

Amount due: EUR 100

Payment intent

The merchant’s desired financial outcome.

Payment Intent PI-8921

Collect EUR 100 for ORD-1842

Payment attempt

One attempt to achieve that intent.

PI-8921

|

+-- PA-1 -> Provider A

Provider transaction

The provider-native object representing that attempt or one of its financial operations.

PA-1

provider = PSP_A

provider_transaction_id = TX-66382

These distinctions matter because one payment intent can involve more than one attempt.

For example:

Payment Intent PI-8921

|

+-- PA-1 -> Provider A -> known decline

|

+-- PA-2 -> Provider B -> authorized

The merchant-level answer to:

Has this order been paid?

cannot be derived safely from whichever provider transaction happened to be read last.

Payment state belongs to the merchant payment model.

Payment intent state and payment-attempt state are related but different

Suppose an order needs one successful EUR 100 payment.

Attempt 1 fails.

Attempt 2 succeeds.

At the attempt level:

PA-1 = FAILED

PA-2 = COMPLETED

At the payment-intent level:

PI-8921 = COMPLETED

If the merchant only stores one payment_status field, these realities become difficult to represent.

That creates problems for:

Retry analysis

Multi-PSP routing

Duplicate detection

Customer support

Provider comparison

Reconciliation

A merchant should therefore decide explicitly:

Which state belongs to the desired payment outcome, and which state belongs to each attempt to achieve it?

The distinction becomes increasingly important as the business adds:

Multiple providers

Retries

Failover

Asynchronous methods

Customer authentication

Canonical state expresses merchant meaning

A canonical payment state is a merchant-defined state whose meaning remains stable even when provider vocabularies differ.

A high-level model might include:

CREATED

REQUIRES_ACTION

SUBMITTED

PENDING

AUTHORIZED

COMPLETED

FAILED

CANCELED

EXPIRED

UNKNOWN

This is an example, not a universal industry state machine.

Different businesses and methods may require:

Fewer states

Additional states

Separate authorization/capture models

Separate refund/reversal models

The design principle is more important than the labels:

Every canonical state should answer a merchant-operational question.

For example:

CREATED

Merchant has created the payment intent or attempt, but it has not yet reached the relevant execution stage.

REQUIRES_ACTION

Further customer action is required.

SUBMITTED

Merchant has submitted the attempt to the relevant payment path but does not yet have the next meaningful result.

PENDING

The payment is progressing through a known non-terminal lifecycle.

AUTHORIZED

The payment has reached an authorization state where that concept applies.

COMPLETED

The merchant-defined successful financial state has been reached.

FAILED

Merchant has reliable evidence that the attempt cannot complete successfully in its current lifecycle.

CANCELED

The attempt was intentionally stopped before normal completion.

EXPIRED

The relevant payment instruction or attempt expired.

UNKNOWN

Merchant cannot currently establish the financial outcome.

The definition behind each state matters more than the word.

Provider-native state should not disappear

Suppose Provider A sends:

status = "CAPTURED"

reason_code = "00"

and the merchant maps that to:

canonical_state = COMPLETED

Store both.

A useful record might look like:

payment_attempt_id: PA-1

canonical_state: COMPLETED

provider: PSP_A

provider_state: "CAPTURED"

provider_reason_code: "00"

provider_transaction_id: "TX-66382"

Why preserve the native state?

Because the canonical state answers:

What does this mean to our systems?

The provider state answers:

What did the financial counterparty actually report?

That detail can matter for:

Provider support

Incident investigation

Dispute research

Reconciliation

API migrations

Provider-specific operations

Canonicalization should reduce provider coupling.

It should not erase evidence.

Normalize semantics, not labels

A dangerous mapping table looks like this:

Provider status

Merchant state

succeeded

COMPLETED

paid

COMPLETED

captured

COMPLETED

processed

COMPLETED

That mapping assumes the words mean the same thing.

They may not.

Before mapping any provider state, establish:

Which financial operation occurred?

Is the state terminal?

Can it transition again?

Is customer action still required?

Has authorization occurred?

Has capture occurred?

Is the result merely processing?

Is settlement implied or separate?

Can the payment later be reversed?

Provider-specific semantics must come from current provider documentation.

Visa Acceptance documentation, for example, exposes explicit AUTHORIZED states and treats capture as a follow-on transaction in applicable card flows, illustrating why authorization and capture should not be collapsed merely because both represent successful progress.

The mapping question should therefore be:

What merchant meaning corresponds to this provider-defined state?

not:

Which canonical word looks most similar?

Authorized is not captured

This is one of the most important distinctions in card payment state.

An authorization generally indicates that the issuer has approved the relevant authorization request and, in applicable flows, funds or credit have been reserved according to the card-payment process.

Capture is a later operation that moves the transaction into the subsequent clearing/settlement lifecycle.

Visa Acceptance’s current documentation explicitly describes capture as a follow-on transaction to authorization in applicable payment flows.

Conceptually:

CREATED

|

v

SUBMITTED

|

v

AUTHORIZED

|

v

CAPTURE OPERATION

|

v

COMPLETED

Do not make:

AUTHORIZED = COMPLETED

unless the merchant’s business definition and provider/payment-method contract genuinely support that interpretation.

For a sale-style transaction where authorization and capture occur together, the state path can legitimately differ.

That is why the state machine should model payment semantics, not force every method through identical stages.

Failed and canceled are different

Both can mean that the attempt did not produce the desired successful payment.

But they describe different histories.

Failed

The attempt encountered an outcome that prevents successful completion in that lifecycle.

Potential examples:

Issuer decline

Payment-method rejection

Provider validation outcome that terminates the attempt

Canceled

The merchant, customer, provider, or applicable system intentionally terminated the attempt before completion.

Possible examples:

Merchant voids an uncaptured transaction

Customer cancels an applicable flow

Merchant explicitly abandons a pending attempt

Why preserve the distinction?

Because operationally they can imply different:

Customer messaging

Retry eligibility

Provider actions

Reporting

Analysis

A cancellation is not necessarily a payment failure.

A failure is not necessarily a cancellation.

Pending and unknown are fundamentally different

This distinction deserves first-class representation.

Pending

The merchant has evidence that the payment is in a known, non-terminal processing state.

Example:

Provider reports:

status = PENDING

The merchant understands that:

A payment object exists

The provider is still processing it

A later result is expected

Unknown

The merchant cannot currently establish whether the financial operation succeeded.

Example:

Merchant sends authorization.

Provider receives request.

Merchant connection closes.

No reliable response is received.

Provider status endpoint is temporarily unavailable.

The merchant does not know whether authorization occurred.

That is:

UNKNOWN

not:

FAILED

The distinction matters because the next safe action differs.

Pending

Usually:

Wait for or retrieve the expected later state.

Unknown

Usually:

Establish financial truth before creating another financial outcome.

A timeout therefore does not automatically create FAILED.

HTTP semantics do not make non-idempotent financial operations safe to repeat simply because a client failed to obtain the response; RFC 9110 distinguishes idempotent methods precisely because repeated requests can otherwise have additional effects.

The detailed recovery decision belongs in Handling Payment API Timeouts.

State management owns the fact that uncertainty must be representable.

Unknown should be measurable, not hidden

Teams often dislike UNKNOWN because it complicates application code.

Removing the state does not remove the uncertainty.

It usually converts uncertainty into an incorrect answer.

For example:

timeout -> FAILED

looks simpler.

But if the authorization actually succeeded, the merchant now has:

merchant state: failed

provider state: authorized

That discrepancy will eventually surface through:

Webhook

Customer complaint

Reconciliation

Refund request

Finance exception

A better architecture admits:

We do not yet know.

Then measures how often that happens and how long those cases remain unresolved.

Event is not state

A payment event represents something that happened or was reported.

A payment state represents the merchant’s current interpretation of the payment.

These are related but not equivalent.

Suppose the merchant receives:

event 1:

payment.pending

event 2:

payment.authorized

event 3:

payment.pending # delayed older event

The third event exists.

That does not mean current state should become PENDING.

This is the difference between:

Event history

What messages or facts have been observed.

Current state

The merchant’s current canonical interpretation after applying transition rules.

The system should preserve both.

Current state is a projection of history

A useful conceptual model is:

EVENT / OBSERVATION HISTORY

|

v

STATE-TRANSITION RULES

|

v

CURRENT CANONICAL STATE

Possible observations include:

Synchronous provider response

Webhook

Status retrieval

Merchant action

Reconciliation result

The current state is therefore not necessarily “the latest webhook value.”

It is the result of applying known facts to the merchant’s state model.

This has an important debugging benefit.

If support asks:

Why is this payment marked completed?

the system should be able to answer something like:

10:00 Attempt created

10:00 Submitted to PSP A

10:00 Provider returned PENDING

10:02 Webhook reported AUTHORIZED

10:05 Capture succeeded

10:05 Merchant state -> COMPLETED

That is much stronger than:

status = completed

with no history explaining why.

Define allowed transitions explicitly

A state machine should define which transitions are legal.

A simplified model might allow:

CREATED

|

+--> REQUIRES_ACTION

|

+--> SUBMITTED

then:

REQUIRES_ACTION

|

+--> SUBMITTED

+--> CANCELED

+--> EXPIRED

and:

SUBMITTED

|

+--> PENDING

+--> AUTHORIZED

+--> COMPLETED

+--> FAILED

+--> UNKNOWN

then, depending on the payment method:

PENDING

|

+--> AUTHORIZED

+--> COMPLETED

+--> FAILED

+--> EXPIRED

+--> UNKNOWN

and for two-step card payments:

AUTHORIZED

|

+--> COMPLETED

+--> CANCELED / REVERSED

This is illustrative.

Do not copy it blindly into production.

The correct state graph depends on:

Payment method

Provider

Merchant fulfillment rules

Authorization/capture model

Asynchronous behavior

Reject invalid backward transitions

Suppose current state is:

COMPLETED

Then an old webhook arrives saying:

PENDING

If the system simply overwrites state:

COMPLETED -> PENDING

the merchant can suddenly believe a paid order is unresolved.

A state transition layer should instead ask:

Is this transition legal given what we already know?

Conceptually:

if transition_allowed(current_state, candidate_state):

apply()

else:

preserve event

flag if necessary

The event should not necessarily be discarded.

It can remain in history for audit and diagnostics.

But not every observed event deserves to become current state.

Terminal state needs a precise definition

A terminal state means:

No further normal state transition is expected for this state machine.

But payment systems have multiple lifecycles.

A card payment might reach:

COMPLETED

and later be:

Refunded

Partially refunded

Disputed

Reversed in an exceptional lifecycle

That does not necessarily mean COMPLETED was never terminal for the payment-attempt execution state.

It may mean refunds and disputes belong to subsequent financial lifecycle objects.

This is why one giant status field often becomes confusing.

Refunds should not necessarily rewrite the original payment state

Suppose:

Payment = COMPLETED

Then the merchant refunds 30% of the amount.

What should payment.status become?

Possible bad answer:

PARTIALLY_REFUNDED

if that single field now destroys the information that the original payment itself completed successfully.

A clearer model can preserve:

Payment execution state

COMPLETED

Refund state

Refund REF-1 = COMPLETED

Financial summary

captured_amount: EUR 100

refunded_amount: EUR 30

net_amount: EUR 70

Likewise, a full refund can be represented without pretending the original capture never happened.

The right model depends on merchant needs, but the general principle is powerful:

Subsequent financial operations should not erase the historical truth of earlier operations.

Reversal is not necessarily refund

These terms are often used interchangeably in product code.

They should not be.

A reversal can unwind or release an authorization depending on the payment flow.

A refund generally returns value after the relevant payment has completed/captured.

Provider and network terminology varies, so confirm exact behavior.

At the merchant-state level, preserve the underlying operation:

authorization

capture

reversal

refund

rather than flattening everything into:

payment.status = reversed

unless that field has a carefully defined purpose.

One payment can have multiple state machines

A sophisticated merchant does not necessarily need one enormous state enum.

It can be cleaner to model separate but related lifecycles.

For example:

Payment intent state

OPEN

COMPLETED

CANCELED

Attempt state

CREATED

REQUIRES_ACTION

PENDING

AUTHORIZED

COMPLETED

FAILED

UNKNOWN

Refund state

CREATED

SUBMITTED

PENDING

COMPLETED

FAILED

UNKNOWN

Dispute state

Maintained separately where relevant.

This keeps each state machine tied to a specific object.

Trying to express everything in:

payment_status

often produces ambiguous states such as:

AUTHORIZED_PARTIALLY_REFUNDED_DISPUTED

which is a sign that several financial dimensions have been collapsed together.

Customer action is not financial success

A customer can:

Complete 3DS

Return from a wallet

Return from a bank redirect

Scan a QR code

without the merchant necessarily having the final payment result.

Therefore:

customer_returned = true

should not automatically mean:

payment = COMPLETED

For asynchronous payment methods, later confirmation may arrive through:

Provider webhook

Status retrieval

Bank/payment-method confirmation

The dedicated Asynchronous Payment Methods article should own the full lifecycle.

State management owns the principle that customer interaction state and financial state are not interchangeable.

Webhook delivery is not payment state

A webhook is an input.

For example:

provider webhook:

"payment.completed"

The merchant still needs to:

Authenticate/validate the event according to provider requirements.

Associate it with the correct payment/attempt.

Determine whether it is new or duplicate.

Interpret the provider-native status.

Validate the state transition.

Persist the resulting state.

Trigger permitted downstream business action.

Current payment-provider documentation demonstrates why webhook handling must remain provider-specific at the transport layer; providers can define distinct signing, retry, schema, and event semantics. The merchant state machine sits downstream of those mechanics rather than being replaced by them.

The dedicated Webhooks for Payment Processing article should own delivery architecture.

Duplicate events should not create duplicate state effects

Suppose the provider sends the same completed-payment event twice.

The merchant may legitimately receive:

event EV-1

event EV-1

The payment should not be:

COMPLETED

COMPLETED

in a way that triggers fulfillment twice.

Store enough identity to make event processing safe.

Conceptually:

if event already processed:

acknowledge

no repeated business side effect

The state itself can already be COMPLETED.

The second delivery changes nothing.

That is a message-processing concern feeding the state machine, not a new payment state.

Preserve provider event time and merchant processing time separately

Distributed systems can deliver information late.

Useful timestamps may include:

Provider event creation time

Merchant event receipt time

Merchant event processing time

State-effective time

Last provider-status verification time

These tell different stories.

Suppose:

provider event occurred: 10:02

merchant received event: 10:07

merchant processed event: 10:08

That five-minute delay can matter during:

Incident analysis

Fulfillment

SLA measurement

Reconciliation

Do not overwrite all of them with one generic:

updated_at

if the distinction is operationally meaningful.

The merchant should own canonical state—but not invent financial truth

This is the most important source-of-truth nuance.

A merchant can define:

Its canonical state names

Transition rules

Business consequences

Historical event model

But it cannot make a payment successful merely by setting:

status = COMPLETED

Provider/acquirer/payment-method information still supplies evidence about what happened financially.

A useful architecture is:

Merchant payment ledger/system = merchant system of record for canonical state, continuously informed and reconciled against authoritative external financial evidence.

That is different from saying:

The merchant database is always right.

It is only reliable if the merchant reconciles it.

Source of truth is really a hierarchy of evidence

Different facts can have different authoritative sources.

For example:

Merchant intent

Merchant is authoritative.

We intended to collect EUR 100.

Provider transaction existence

Provider can be authoritative.

Transaction TX-66382 exists.

Merchant canonical interpretation

Merchant owns the mapping.

TX-66382 means PA-1 is currently AUTHORIZED.

Settlement

Relevant acquiring/provider/financial records become critical evidence.

This captured transaction appears in settlement batch X.

That produces a more accurate model than trying to name one universal “source of truth.”

Reconciliation is part of state management

State management is not complete when the last webhook arrives.

A merchant can believe:

COMPLETED

while the provider later reports something inconsistent in:

Transaction retrieval

Settlement

Refund

Reversal records

A reconciliation process should therefore test whether merchant state agrees with relevant financial records.

Conceptually:

MERCHANT STATE

|

+------ compare ------ PROVIDER STATE

|

+------ compare ------ FINANCIAL / SETTLEMENT RECORD

|

v

CONSISTENT

or

RECONCILIATION EXCEPTION

The finance mechanics belong in broader reconciliation content.

But the state architecture must preserve enough identifiers to make the comparison possible.

Reconciliation should create evidence, not silently overwrite history

Suppose the merchant has:

PA-1 = UNKNOWN

and later reconciliation proves:

Provider = AUTHORIZED

The system can transition:

UNKNOWN -> AUTHORIZED

but it should ideally preserve why.

For example:

state_before: UNKNOWN

state_after: AUTHORIZED

source: reconciliation_status_query

observed_at: ...

provider_state: AUTHORIZED

Do not silently rewrite the old record as though the merchant had always known the payment was authorized.

The uncertainty itself can be operationally important.

Model state provenance

For each state change, useful fields can include:

payment_attempt_id

previous_state

new_state

source_type

source_id

provider

provider_state

provider_transaction_id

provider_event_time

merchant_received_time

merchant_processed_time

reason_code

transition_version

Possible source_type values might include:

api_response

webhook

status_query

reconciliation

merchant_action

system_action

This creates an audit trail capable of answering:

What evidence caused this state change?

Version the transition logic

Payment systems change.

A state mapping that was correct under:

provider API version X

may need modification under:

provider API version Y

Likewise, the merchant may refine its canonical state model over time.

If state behavior materially changes, store or log enough information to determine:

Provider/API version

Mapping version

Merchant transition-rule version

That makes production investigations much easier.

Do not assume a current state mapping will remain semantically stable forever.

New provider statuses must not crash the payment system

Providers can expand enumerations.

A merchant that writes:

switch provider_status:

case "AUTHORIZED":

case "DECLINED":

case "PENDING":

default:

crash()

has created fragility.

A safer philosophy is:

known provider state

-> mapped canonical meaning

unknown new provider state

-> preserve raw value

-> avoid unsafe financial assumption

-> alert / investigate

Do not map an unknown value automatically to FAILED.

Unknown provider vocabulary should not produce invented financial truth.

State mapping should be provider and payment-method aware

The same provider may expose different lifecycles for:

Cards

Wallets

Bank transfers

Other local methods

Therefore:

provider_status -> canonical_state

may be insufficient.

A more accurate mapping key can require:

provider

payment_method

operation

provider_status

and sometimes additional context.

That prevents a card-specific interpretation from being incorrectly applied to an asynchronous method.

A practical Canonical State Mapping Template

For each provider/method, maintain a reviewed mapping.

Provider state

Operation/method

Canonical state

Terminal?

Customer action?

Financial meaning

Allowed next states

AUTHORIZED

Card auth

AUTHORIZED

No

No

Authorization approved

COMPLETED, CANCELED/REVERSED

PENDING

Provider-defined

PENDING

No

Depends

Provider still processing

Provider-specific

DECLINED

Card auth

FAILED

Usually attempt-terminal

Possibly new attempt later

Authorization declined

—

Unknown new enum

Any

UNKNOWN/REVIEW

No assumption

Unknown

Not yet mapped safely

Investigate

Rows are illustrative only.

Each provider mapping must be verified against current documentation.

State machine guards should include business invariants

Transition rules can validate more than status order.

Examples:

Amount invariant

A completion event should correspond to the amount/currency expected for that financial operation.

Provider identity

An event must correspond to the provider/merchant account that owns the attempt.

Operation lineage

A capture must refer to an applicable authorization.

Visa Acceptance documentation, for example, describes capture as a follow-on transaction using the authorization transaction identifier in applicable flows.

Refund limit

Cumulative successful refunds should not exceed the refundable amount according to the merchant/provider lifecycle unless the specific payment system allows another behavior.

These checks help prevent correct-looking states from being attached to the wrong financial object.

Concurrency can corrupt otherwise correct state logic

Payment state can be updated simultaneously by:

API-response handler

Webhook worker

Status-reconciliation job

Customer request

Operations tool

Example:

Thread A reads: PENDING

Thread B reads: PENDING

Thread A writes: AUTHORIZED

Thread B writes: FAILED

Which wins?

Without concurrency control, the answer may simply be:

whichever database write happened last.

That is not a financial state model.

Possible implementation techniques include:

Optimistic versioning

Compare-and-set

Row locking

Serialized state transitions

Event-stream ordering within a payment aggregate

The right mechanism depends on architecture.

The requirement is that state transitions are atomic enough at the merchant boundary to preserve invariants.

Maintain a current-state view and an immutable history where practical

The merchant usually needs fast access to:

current_state = AUTHORIZED

But investigations need history.

A useful pattern is:

Current payment record

Optimized for operational reads.

State-transition history/event log

Records how the current state was reached.

Conceptually:

Current:

PA-1 = AUTHORIZED

History:

10:00 CREATED

10:00 SUBMITTED

10:01 PENDING

10:03 AUTHORIZED

The history does not need to imply full event-sourcing architecture.

The simpler principle is:

Do not throw away the sequence of financially meaningful state changes.

Separate state from side effects

A state transition can trigger business actions such as:

Fulfillment

Customer notification

Entitlement

Invoice generation

But make those relationships explicit.

For example:

payment state -> COMPLETED

|

v

publish merchant event

|

v

fulfillment service acts idempotently

rather than tightly coupling:

process PSP webhook

-> ship order directly

Why?

Because the same payment state might later be established through:

Synchronous response

Webhook

Status query

Reconciliation

The business action should depend on the merchant state transition, not one transport mechanism.

Define fulfillment state separately from payment state

A paid order can still be:

NOT_FULFILLED

A refunded payment can correspond to an already delivered order.

Therefore do not overload payment state with:

Shipping state

Entitlement state

Order fulfillment state

A useful conceptual relationship is:

ORDER STATE

PAYMENT STATE

FULFILLMENT STATE

REFUND STATE

related, but distinct.

This separation becomes essential when partial capture, partial fulfillment, partial refunds, or asynchronous methods enter the system.

State should survive provider migration

Suppose the merchant migrates from PSP A to PSP B.

Old payments remain:

PA-OLD

provider = PSP_A

canonical_state = COMPLETED

New payments become:

PA-NEW

provider = PSP_B

canonical_state = COMPLETED

Customer support can reason about both through one merchant vocabulary while still retaining the provider-specific transaction history needed for:

Refunds

Disputes

Reconciliation

That is one of the major architectural benefits of merchant-owned state.

The merchant does not need to rewrite historical business meaning because the provider changed.

Do not normalize away provider-specific financial capabilities

Canonical state does not imply provider equivalence.

Provider A may support:

Partial capture

Provider B may not.

Provider C may represent:

Delayed settlement confirmation

differently.

Preserve those capabilities separately from state.

For example:

canonical_state = AUTHORIZED

capabilities:

partial_capture = true

The state tells the merchant where the payment is.

Capability tells the merchant which operation can happen next.

Those are different concerns.

The Merchant Payment State Machine

A useful high-level state model is:

┌─────────────┐

│ CREATED │

└──────┬──────┘

|

┌─────────┴─────────┐

| |

v v

REQUIRES_ACTION SUBMITTED

| |

| |

└─────────┬─────────┘

|

┌────────────────┼────────────────┐

| | |

v v v

PENDING AUTHORIZED UNKNOWN

| | |

| | |

v v |

COMPLETED COMPLETED |

| |

| resolve via

| status/event/reconcile

| |

| ┌────────────────┼──────────────┐

| v v v

| PENDING AUTHORIZED FAILED

|

+--------------------------------------------

Other terminal/attempt-ending paths:

FAILED

CANCELED

EXPIRED

This is not a universal payment state machine.

Its purpose is to expose the important merchant distinctions:

Customer action

Known processing

Authorization

Completion

Known failure

Intentional cancellation

Expiration

Uncertainty

Refunds and reversals should generally be modeled as subsequent financial lifecycle operations rather than pretending they erase what happened earlier.

Add an explicit state-transition record

A practical state-transition record might contain:

transition_id

payment_intent_id

payment_attempt_id

from_state

to_state

transition_source

source_reference

provider

provider_transaction_id

provider_native_state

financial_operation

event_created_at

received_at

processed_at

mapping_version

reason

This allows:

Audit

Incident review

Provider debugging

Reconciliation

State-model migrations

without requiring engineers to reverse-engineer state from logs months later.

Measure state quality

Payment state is infrastructure.

It needs operational metrics.

Unknown-state backlog

Count of attempts still in UNKNOWN beyond the merchant-defined investigation interval.

Useful because uncertainty that never resolves is an operational debt queue.

Unknown-state rate

initiated attemptsattempts entering unresolved unknown state​×100

Define the interval and population precisely.

Invalid transition count

Number of attempted transitions rejected by state rules.

Break down by:

Provider

Method

Event type

Integration version

A rise can reveal:

Out-of-order events

Changed provider behavior

Incorrect mappings

Software defects

State conflict rate

payments evaluatedpayments where material data sources disagree on state​×100

For example:

merchant = FAILED

provider = AUTHORIZED

Define what counts as a material conflict.

Reconciliation exception rate

payment records reconciledpayment records requiring manual state investigation​×100

This connects engineering quality to Finance workload.

Manual payment investigation rate

eligible payment casespayment cases requiring human state investigation​×100

Useful for measuring whether state architecture actually scales operationally.

Alerts should focus on contradictions

A useful state system does not merely alert on:

payment failed

Failures can be normal.

More important signals can include:

UNKNOWN aging beyond threshold

Invalid transition spike

Merchant/provider state disagreement

Completed payment lacking expected financial reference

Refund state inconsistent with provider

Sudden appearance of unmapped provider statuses

Webhook/state-processing backlog

Those are signs the merchant may no longer understand its own payment truth.

Testing should attack the state machine, not just the happy path

A useful test suite includes:

Valid progression

CREATED -> SUBMITTED -> AUTHORIZED -> COMPLETED

Customer-action progression

CREATED -> REQUIRES_ACTION -> SUBMITTED -> AUTHORIZED

Pending progression

SUBMITTED -> PENDING -> COMPLETED

Known failure

SUBMITTED -> FAILED

Uncertain outcome

SUBMITTED -> UNKNOWN -> AUTHORIZED

Duplicate event

Same event processed twice, state changes once.

Out-of-order event

AUTHORIZED processed before older PENDING; current state does not regress.

Concurrent updates

API response and webhook attempt state change simultaneously.

Unknown provider enum

Raw status preserved; no unsafe automatic financial conclusion.

The Payment Sandbox Best Practices article should own the larger testing methodology.

Here, the requirement is simply:

Test state invariants, not only provider endpoint responses.

The simplest useful state model should win

Not every merchant needs twenty-five canonical states.

Too few states create ambiguity.

Too many can create operational complexity no system actually uses.

A good design criterion is:

Does this distinction change merchant behavior?

For example, preserving:

PENDING vs UNKNOWN

is valuable because recovery behavior differs.

Preserving:

AUTHORIZED vs COMPLETED

is valuable when capture matters.

Creating four merchant states corresponding to four PSP-internal processing labels may add no useful business distinction.

Canonicalization should reduce noise.

Not recreate provider complexity under new names.

A payment state machine is not an analytics taxonomy

Operations and analytics may want additional dimensions such as:

Decline category

Authentication result

Provider route

Issuer

Fraud result

Settlement state

Do not force all of them into one payment-state enum.

A state machine should primarily answer:

Where is this payment in its merchant-relevant lifecycle?

Analytics can attach richer attributes.

This separation keeps state transitions understandable.

Payment state should be inspectable by humans

A support or payment-operations tool should ideally show more than:

Status: FAILED

Useful context can include:

Merchant payment: PI-8921

Attempt: PA-2

Canonical state: FAILED

Provider: PSP B

Provider state: DECLINED

Provider code: ...

Provider transaction: ...

Previous state: SUBMITTED

Transition source: synchronous API response

Timestamp: ...

For an unknown payment:

Canonical state: UNKNOWN

Reason: request timed out after submission

Last provider lookup: unavailable

Next reconciliation action: scheduled status query

This reduces dependence on engineers querying several systems to reconstruct every payment.

Document the semantics, not just the enum

A state definition should specify:

Meaning

What is known?

Financial implication

What operation has occurred?

Terminal?

Can normal execution continue?

Allowed next states

What transitions are legal?

Merchant actions

Can the order be fulfilled?

Recovery

What should happen if state remains here?

Provider mapping

Which native provider states can map here?

That produces documentation such as:

Canonical state

Meaning

Terminal?

Fulfillment?

Recovery

CREATED

Merchant object exists; no relevant execution yet

No

No

Continue

REQUIRES_ACTION

Customer step required

No

No

Resume customer flow

PENDING

Known nonterminal provider/method state

No

Usually no unless policy says otherwise

Await event/status

AUTHORIZED

Authorization succeeded where applicable

No or business-dependent

Merchant-policy dependent

Capture/void

COMPLETED

Merchant-defined successful completion

Often execution-terminal

Usually eligible

Reconcile

FAILED

Known unsuccessful attempt

Attempt-terminal

No

New attempt if appropriate

UNKNOWN

Outcome cannot currently be established

No

No

Resolve before unsafe retry

Illustrative only; each merchant must define its own semantics.

Until those details are verified, the appropriate positioning is architectural:

A payment provider can expose transaction states and events, but merchants operating across methods, markets, or providers benefit from maintaining a stable internal interpretation of payment state while retaining the provider-native identifiers and status detail required for support and financial reconciliation.

Universal canonical states

Guaranteed event ordering

Exactly-once callbacks

Automatic reconciliation

Cross-provider state normalization

without direct evidence.

Final recommendation

Do not ask:

What status does the PSP return?

Ask:

What does the merchant know about this payment now, what financial operation has occurred, which evidence supports that conclusion, and what transitions remain valid?

Then design state around those answers.

Keep:

Payment intent

separate from:

Payment attempt.

Keep:

Canonical state

alongside:

Provider-native state.

Keep:

Authorized

separate from:

Completed/captured.

Keep:

Failed

separate from:

Canceled.

Keep:

Pending

separate from:

Unknown.

Keep:

Current state

separate from:

State history.

And treat:

API responses

Webhooks

Status queries

Reconciliation

as sources of evidence that update merchant state, not as independent versions of payment truth competing with one another.

The provider should remain authoritative about the transaction behavior it actually executed.

The merchant should remain authoritative about what those facts mean within its own payment system.

And reconciliation should be the process that proves the two have not drifted apart.

That is the real purpose of payment state management:

to maintain a durable, explainable, financially correct representation of the payment even when providers use different vocabularies, events arrive asynchronously, systems disagree temporarily, and the payment continues changing long after the original API request has ended.

This article provides general information and does not constitute legal, regulatory, security, financial, network-rule, or compliance advice. Payment states, event behavior, authorization/capture semantics, refund mechanics, and status APIs vary by provider, payment method, network, jurisdiction, and product. Merchants should verify current behavior with the relevant payment providers and qualified payments, engineering, security, and compliance specialists.

🙂 🙂 🙂 🙂 🙂 🙂 🙂

The brief makes this article the cluster’s merchant-payment-truth article. Its job is not to teach webhook delivery or timeout recovery in depth; it should define the durable state model those mechanisms update. The strongest architecture is merchant-owned canonical state plus preserved provider-native detail, with reconciliation as the mechanism that keeps the two aligned over time.

Brief interpretation

Merchant engineering problem: Multiple providers expose incompatible payment statuses, so business logic becomes tied to PSP-specific words such as succeeded, captured, paid, processing, or pending.

Unique evidence anchor: The provider knows the status of its own transaction. The merchant still needs a durable model describing what that transaction means to the merchant.

Editorial position: Canonical state should normalize business meaning without erasing financially useful provider information.

Common assumption challenged: “We can just store the PSP status.”

Primary system boundary: Provider-native transaction state ↔ merchant-owned payment state.

Primary technical distinction: Current canonical state versus the event/history that produced it.

Merchant decision: Which payment facts should become stable merchant semantics, and which provider-native details should remain attached for reconciliation, support, and financial operations?

Selected format: State-machine design.

Structural rationale: Start with the semantic mismatch between providers, establish merchant intent and attempts, define canonical states and legal transitions, then show how API responses, webhooks, polling, and reconciliation update—not replace—the merchant state model.

ARTICLE

SEO, EDITORIAL & PRODUCTION ADVICE

Payment State Management: How to Design a Payment State Machine

H1

Payment State Management: Designing a Reliable Payment State Machine

Meta title

Payment State Management | Payment State Machine Guide

Meta description

Learn how to design merchant-owned payment states across PSPs, including intents, attempts, pending vs unknown, authorization vs capture, canonical state, event history, and reconciliation.

URL slug

/payment-state-management/

payment state management

Secondary keywords

Prioritize naturally:

payment state machine

payment status lifecycle

payment processing states

payment intent state

payment transaction status

payment status architecture

payment lifecycle states

payment status management

payment state model

canonical payment state

Related entities

Payment intent

Payment attempt

PSP

Payment gateway

Authorization

Capture

Refund

Reversal

Webhook

Event

Payment status

Reconciliation

Idempotency

Asynchronous payment

Article excerpt

Payment providers expose their own transaction statuses, but merchants still need a durable payment-state model that describes what each payment means to the business. A reliable payment state machine separates payment intent from attempts, canonical state from provider-native state, pending from unknown, and current state from the history and evidence used to derive it.

Featured-snippet opportunity

Use high on the page:

What is payment state management?

Payment state management is the merchant-side process of maintaining a durable representation of a payment’s lifecycle using explicit states and transition rules. It translates provider-native statuses into stable merchant meaning while preserving provider detail, asynchronous event history, and reconciliation evidence.

Original practical asset

Merchant Payment State Machine

Recommended primary graphic:

CREATED

|

┌─────────────┴─────────────┐

| |

v v

REQUIRES_ACTION SUBMITTED

| |

└─────────────┬─────────────┘

|

┌─────────────────┼──────────────────┐

| | |

v v v

PENDING AUTHORIZED UNKNOWN

| | |

┌─────┴─────┐ | ┌───────┼───────┐

| | | | | |

v v v v v v

COMPLETED FAILED COMPLETED PENDING AUTHORIZED FAILED

Other attempt-ending states:

CANCELED | EXPIRED

Subsequent financial lifecycle:

COMPLETED

|

+--> REFUND OBJECT(S)

|

+--> REVERSAL / DISPUTE LIFECYCLE AS APPLICABLE

Visual caption

Merchant state should normalize business meaning while preserving the provider-native transaction evidence that produced each transition.

Alt text

Merchant payment state machine showing created, requires action, submitted, pending, authorized, unknown, completed, failed, canceled and expired states, with unknown payments resolved through later evidence and refunds tracked as subsequent financial operations.

Canonical State Mapping Template

A second, highly useful article asset:

Field

Purpose

Provider

Which PSP/payment system

Payment method

Card, wallet, bank method, etc.

Operation

Create, authorize, capture, refund

Provider-native state

Exact current documented status

Canonical merchant state

Merchant business interpretation

Financial meaning

What has actually occurred

Terminal?

Whether normal attempt execution ends

Customer action?

Whether customer must do anything

Allowed next states

Valid merchant transitions

Fulfillment implication

Whether merchant may fulfill

Reconciliation evidence

IDs/data required later

Mapping version

Which rule version produced interpretation

This is the operational artifact I would recommend engineering maintain alongside the code.

Internal-link recommendations

Payment API Integration Guide

Use near the payment-object definitions.

Suggested anchor:

how payment intents and attempts fit into a production payment API integration

Boundary: that article owns the overall API architecture.

Webhooks for Payment Processing

Use from event-vs-state discussion.

Suggested anchor:

how to receive and process payment webhooks safely

Boundary: Webhooks owns delivery, validation, retries, duplicate receipt, and processing pipelines.

Asynchronous Payment Methods

Use from pending/customer-action sections.

Suggested anchor:

designing asynchronous payment lifecycles

Boundary: that article owns redirects, delayed confirmation, expiration, and customer return behavior.

Handling Payment API Timeouts

Recommended additional contextual link from UNKNOWN.

Suggested anchor:

how to resolve an unknown payment after an API timeout

Payment Idempotency Explained

Optional link where state uncertainty intersects retry safety.

Suggested anchor:

using idempotency for repeated financial operations

Authoritative source recommendations

This article should rely lightly on provider-specific documentation because the state model itself is a merchant architecture recommendation.

Visa Acceptance — authorization/capture semantics

Current Visa Acceptance documentation is useful as primary evidence that authorization and capture are separate operations in applicable card flows. Capture documentation describes capture as a follow-on transaction tied to the authorization transaction.

This supports the article’s distinction:

authorized ≠ necessarily completed.

Do not generalize exact Visa states to other PSPs or payment methods.

IETF RFC 9110

RFC 9110 is useful where payment-state uncertainty intersects transport failure and retries. HTTP defines idempotent methods based on the intended effect of repeated requests; it does not imply that arbitrary repeated financial POST operations are harmless after an uncertain response.

Keep the deep idempotency discussion in the dedicated article.

PCI SSC

PCI SSC is relevant only if the final implementation discussion expands into storage/logging of payment credentials. PCI DSS applies to environments that store, process, transmit, or can impact the security of payment account data.

State-management records should generally use identifiers and non-sensitive operational metadata rather than sensitive account credentials.

Proposed author and reviewers

Proposed author: Senior payment-platform engineer or payment architect.

Relevant experience should include:

Payment state machines

Multi-PSP integrations

Asynchronous event processing

Financial reconciliation

Primary technical reviewer: Senior backend/payment engineer.

Review:

Intent/attempt distinction

Canonical states

Transition invariants

Concurrency

State history

Provider mapping

Payment Operations reviewer: Validate:

Investigation workflows

Provider-native information

State visibility

Manual exception handling

Finance/reconciliation reviewer: Validate:

Authorization/capture/refund lineage

Settlement references

Reconciliation-conflict treatment

First-hand contribution opportunity

A particularly strong contribution would be an approved state-reconstruction case.

For example:

Merchant state before incident

→ provider event sequence

→ incorrect transition

→ financial discrepancy

→ revised state model/guard

→ measured reduction in manual exceptions

Potential evidence could include:

Unknown-state backlog

Invalid-transition counts

Reconciliation exceptions

Manual investigation volume

Do not invent the incident or metrics.

A strong expert prompt is:

Which provider status or event sequence most clearly demonstrated that storing the PSP’s status directly was not a sufficient merchant payment model?

Technical fact-check items

For each provider/payment method represented in a mapping table, verify:

Exact current provider state names

Meaning of each state

Terminal/non-terminal behavior

Whether customer action remains

Whether authorization occurred

Whether capture occurred

Whether later reversal is possible

Whether status can change after apparent completion

Whether provider exposes separate payment/authorization/capture objects

Whether status retrieval exists

Do not map by vocabulary alone.

Payment-state assumptions requiring verification

Before publication of any specific transition such as:

AUTHORIZED -> COMPLETED

verify:

Provider

API/product

Payment method

Merchant transaction type

Authorization/capture model

Current documentation

Likewise verify whether:

PENDING can become FAILED

PENDING can expire

COMPLETED is terminal

CANCELED can later receive a late success

UNKNOWN can be queried

Refund status is synchronous or asynchronous

Webhook/state fact-check items

For each provider verify:

Event type

Event ID

Native state in payload

Duplicate-delivery behavior

Ordering guarantees, if any

Event-created timestamp

Retry behavior

Replay support

Signature/authentication

Whether event means state changed or merely that a provider process occurred

Never assume event arrival order equals financial state order.

Concurrency fact-check items

Review implementation behavior for simultaneous:

API callback + webhook

Duplicate webhooks

Two status jobs

Customer retry + provider event

Concurrent capture/refund operations

Verify the system has:

Version/locking control

Transition validation

Idempotent side-effect handling

Transaction-history preservation

Reconciliation requirements

The state model should retain enough identifiers to compare:

ORDER

↓

PAYMENT INTENT

↓

ATTEMPT

↓

PROVIDER TRANSACTION

↓

AUTHORIZATION / CAPTURE

↓

REFUND / REVERSAL

↓

SETTLEMENT

Reconciliation should be able to detect at least:

Merchant says completed; provider does not

Provider says completed; merchant does not

Merchant says failed; provider shows authorized/captured

Refund state disagreement

Missing provider transaction reference

Unexpected amount/currency mismatch

The detailed financial matching methodology belongs to the reconciliation cluster.

State-observability schema

Useful non-sensitive fields can include:

payment_intent_id

payment_attempt_id

order_id

canonical_state

previous_canonical_state

provider

provider_transaction_id

provider_native_state

provider_reason_code

operation

transition_source

source_reference

event_created_at

received_at

processed_at

mapping_version

integration_version

last_provider_status_check

reconciliation_status

Do not include raw card credentials or secrets.

Metric definitions

Unknown-state backlog

Count of payment attempts remaining in merchant-defined UNKNOWN state beyond the investigation interval.

Always define that interval.

Invalid-transition rate

state-transition attemptsrejected invalid state transitions​×100

Useful by provider/method/integration version.

State-conflict rate

payments evaluated for conflictpayments with material merchant/provider state disagreement​×100

Define material disagreement explicitly.

Reconciliation-exception rate

payment records reconciledpayment records requiring manual state investigation​×100

Manual-payment-investigation rate

eligible paymentspayments requiring human state investigation​×100

These metrics make “good state management” operationally measurable rather than architectural rhetoric.

API/version fact-check items

State mapping is vulnerable to API change.

For every provider maintain:

API version

Event/webhook schema version

Integration version

Known status enumeration

Last status-definition review

Mapping-rule version

Deprecated state values

Newly introduced state values

A provider adding an enum value can be operationally breaking even if the provider regards the change as backward-compatible.

Unknown status values should fail safely into investigation rather than fabricated state.

Sandbox/test requirements

The sandbox/test plan should attempt, where supported, to exercise:

Successful state progression

Known failure

Customer action

Pending state

Timeout/unknown

Duplicate event

Out-of-order event

Repeated status response

Invalid transition

Authorization/capture

Refund state

Concurrency

Do not claim the sandbox can reproduce every production state transition unless the provider documents that capability.

Migration implications

Merchant-owned canonical state can reduce provider migration coupling, but verify:

Legacy provider transactions remain retrievable

Refunds against legacy payments remain possible

Dispute references remain available

Provider-native history is retained

Old state mappings remain interpretable

New provider statuses can map into the merchant model without rewriting historical states

Do not rewrite historical provider-native values to make them resemble the new PSP.

Security fact-check items

Payment state storage should be reviewed to ensure it does not inadvertently contain:

PAN

CVV

Secret keys

Access tokens

Sensitive authentication data

PCI DSS applies to environments that store, process, transmit, or can affect the security of payment account data.

A state machine does not need sensitive credentials merely to describe financial state.

Objects and identifiers

Authorization/capture IDs where applicable

Refund IDs

Status model

State definitions

Terminal states

Pending states

Failure states

Cancellation/expiration states

Method differences

Card lifecycle

Wallet lifecycle

Bank/local-payment lifecycle

Async method states

Events

Callback/webhook mechanism

Event identifiers

Delivery behavior

Authentication/signature

Retry

Ordering

State retrieval

Status/query APIs

Queryable identifiers

Timing/availability

Financial lifecycle

Authorization

Capture

Void/reversal

Refund

Partial refund

Reconciliation

Reporting identifiers

Settlement linkage

Payment/refund references

Until verified, avoid claims such as:

Amber-flag claims

Require current evidence before saying:

succeeded universally means captured.

paid universally means settled.

processing and pending are interchangeable.

failed means no financial action occurred.

canceled means a payment can never arrive later.

A timeout means UNKNOWN for every provider circumstance.

Every payment method uses authorization.

Every authorization must be captured.

Every webhook indicates a state transition.

Webhooks arrive in order.

Latest event always represents current state.

Provider status is authoritative for merchant fulfillment.

Merchant database alone is authoritative financial truth.

Refunds should overwrite payment state.

One canonical state machine works for every payment method.

Cluster sameness audit

Article: Payment State Management

Opening device: Semantic comparison of provider statuses—succeeded, captured, paid—rather than another API-failure scenario.

Merchant engineering problem: Provider-native statuses leak into merchant business logic and create incompatible interpretations.

Integration lifecycle stage: Runtime financial-state management.

Primary system boundary: Provider-native transaction state ↔ merchant canonical state.

Primary technical distinction: Current canonical state vs event/history.

Secondary distinctions: intent vs attempt; authorization vs capture; failed vs canceled; pending vs unknown; event vs state.

Primary format: State-machine design.

Unique evidence anchor: Provider understands its transaction; merchant still needs durable merchant meaning.

Editorial position: Normalize business semantics while retaining provider-native evidence.

Original framework: Merchant Payment State Machine.

Secondary asset: Canonical State Mapping Template.

Main technical risk: Incorrect transitions create false financial truth even when every upstream event was technically valid.

Primary metrics: Unknown-state backlog, invalid transitions, state conflicts, reconciliation exceptions, manual investigations.

Merchant decision: Which meanings belong in stable merchant state, and which provider details should remain contextual evidence?

Conclusion: Merchant state is a durable, reconciled interpretation of financial evidence—not a copy of the last PSP status observed.

Primary internal links: Payment API Integration Guide → Webhooks for Payment Processing → Asynchronous Payment Methods → Handling Payment API Timeouts.

Boundary: Does not own webhook-delivery implementation, timeout recovery procedure, idempotency-key design, or the full asynchronous-payment lifecycle.

That gives the article a distinct role in the cluster: the API article explains how payments are executed; the webhook article explains how events arrive; the timeout article explains uncertainty; Payment State Management explains how all of those inputs become one durable and auditable merchant interpretation of the payment.

Need help narrowing down payment options?

Answer a few questions about your business and compare the capabilities that matter to you.

Explore matching options ↗
EXPLORE PAYMENT INTELLIGENCE