> ## Documentation Index
> Fetch the complete documentation index at: https://docs.dynamic.xyz/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Payment lifecycle and states

> The execution, settlement, and risk states of a Flow payment, what moves a flow between them, what can change before the payment is sent, and which amounts to show.

A Flow payment moves through states on three independent axes. This page describes every state, who or what moves the flow into it, what can still change, and which amounts a flow reports along the way.

## Three axes and when a payment is done

A flow has no single status field. Instead, it reports three:

| Axis | Field | Tracks |
| - | - | - |
| Execution | `executionState` | What the payer and their payment source have done |
| Settlement | `settlementState` | Delivery of the funds to your destination |
| Risk | `riskState` | The screening result for the payment source |

A payment is done when `settlementState` is `completed`. A payment has failed when `executionState` or `settlementState` is `failed`.

Settlement starts only after execution reaches `source_confirmed`. Reaching `source_confirmed` means the payer's funds arrived, but delivery to your destination can still be in progress or can still fail, so do not fulfill an order on `source_confirmed` alone.

## Execution states

| State | Meaning | Moved there by |
| - | - | - |
| `initiated` | The flow exists, and no payment source is attached yet | Your server, when it creates the flow |
| `source_attached` | The payer chose a payment source | The payer |
| `quoted` | A quote exists. For a deposit address, the address is ready to receive funds | The payer |
| `signing` | The payer is approving a wallet payment | The payer |
| `broadcasted` | The payer's wallet sent the transaction to the network | The payer |
| `source_detected` | A deposit reached the deposit address and is being confirmed | Dynamic |
| `source_confirmed` | The payer's funds arrived. Settlement continues on the settlement axis | Dynamic |
| `cancelled` | The flow was cancelled before the payment was sent | The payer or your server |
| `expired` | The flow reached its expiry time before the payment was sent | Dynamic |
| `failed` | The payment failed. The flow's `failure` field says why | Dynamic |

`cancelled`, `expired`, and `failed` are final. `source_confirmed` is final on the execution axis, and the flow continues on the settlement axis.

The states `initiated`, `source_attached`, `quoted`, and `signing` come before the payment is sent. In those states the payer can switch source, and the flow can be cancelled or can expire. Once a flow reaches `broadcasted` or `source_detected`, neither the payer nor your server can change it, and the flow ends in `source_confirmed` or `failed`.

The following diagram shows how a payment moves forward on the execution axis. Any state before the payment is sent can also move to `cancelled` or `expired`, and any state other than `initiated` and `source_confirmed` can move to `failed`.

```mermaid theme={"system"}
stateDiagram-v2
    [*] --> initiated: your server creates the flow
    initiated --> source_attached: payer attaches a source
    source_attached --> quoted: payer requests a quote
    quoted --> source_attached: payer switches source
    quoted --> quoted: payer requests a new quote
    quoted --> signing: payer approves a wallet payment
    signing --> quoted: payer requests a new quote
    signing --> broadcasted: wallet transaction sent
    broadcasted --> source_confirmed: transaction confirmed
    quoted --> source_detected: deposit seen
    source_detected --> source_confirmed: deposit confirmed
    quoted --> source_confirmed: deposit confirmed
    source_attached --> source_confirmed: exchange confirms the purchase
    source_confirmed --> [*]: settlement continues
```

## Settlement states

| State | Meaning |
| - | - |
| `none` | Nothing has been delivered yet. Every flow starts here |
| `settling` | The payment is being converted and delivered with a swap or bridge |
| `completed` | The funds reached your destination. The payment is done |
| `failed` | Delivery failed. Execution stays at `source_confirmed`, and the flow's `failure` says why |

A payment that needs a swap or bridge moves from `none` to `settling` and then to `completed` or `failed`. A direct wallet transfer, a deposit-address payment, and an exchange payment move from `none` straight to `completed`.

```mermaid theme={"system"}
stateDiagram-v2
    [*] --> none
    none --> completed: direct, deposit address, or exchange
    none --> settling: swap or bridge needed
    settling --> completed: delivered
    settling --> failed: delivery failed
    completed --> [*]
    failed --> [*]
```

## Risk states

| State | Meaning |
| - | - |
| `unknown` | Screening did not return a result. The payment can continue. |
| `cleared` | The wallet passed screening, or the payer chose a source that Dynamic does not screen |
| `blocked` | The wallet was blocked by screening. The payer cannot pay from it but can choose another source |

`cleared` on an exchange or deposit-address payment does not mean the funder was screened. A blocked result does not change the execution state, so the payer can attach a different source to the same flow. [Screening](https://docs.dynamic.xyz/docs/flow/screening.md) explains when screening runs.

## Paths by payment source

| Payment source | Execution | Settlement |
| - | - | - |
| Wallet, same token and chain as a settlement | `initiated` → `source_attached` → `quoted` → `signing` → `broadcasted` → `source_confirmed` | `none` → `completed` |
| Wallet, conversion needed | `initiated` → `source_attached` → `quoted` → `signing` → `broadcasted` → `source_confirmed` | `none` → `settling` → `completed` |
| Deposit address | `initiated` → `source_attached` → `quoted` → `source_detected` → `source_confirmed` | `none` → `completed` |
| Exchange | `initiated` → `source_attached` → `source_confirmed` | `none` → `completed` |

A deposit-address flow can also move from `quoted` straight to `source_confirmed` without reporting `source_detected`. In a `withdraw` flow, your platform's wallet is the wallet source and signs the payment.

## What can change and until when

| What | Can change |
| - | - |
| Payment source | Until the payment is sent (`broadcasted` or `source_detected`). From `signing`, only in the payer's current session |
| Amount | Only in `deposit` mode, when the payer requests a quote. The new amount replaces the flow's `amount`, and a wallet source is screened again |
| Quote | The payer can request a new quote from `source_attached`, `quoted`, or `signing`. Each new quote replaces the previous one |
| Risk | Before the payment is sent. Each time the payer attaches a source, the risk state is set again for that source. It never changes after the payment is sent |
| Flow configuration | Never. Settlement tokens, destinations, fees, expiry, and display settings (`uiConfig`) are fixed when the flow is created |

## Resuming a flow

A payer can leave and come back, and how the payment resumes depends on where they come back.

When the payer attaches a source, the flow issues a session token, and the SDK stores it on the payer's device. That token is required for every step after attaching: quoting, approving, reporting the transaction, and cancelling. Reading the flow needs only the flow ID.

* **Same browser or app.** The stored token is still there, so the payer resumes from the flow's current state.
* **Another device, or cleared storage.** The page can read the flow, but it has no token. Before the payment is sent, the payer attaches a source again. That issues a new token on the new device, and the token on the old device stops working. After the payment is sent, nothing is left for the payer to do, and the page only shows progress.

A page that reloads while the flow is in `signing` cannot tell whether the payer already approved the payment in their wallet. Treat the payment as processing and keep reading the flow instead of asking the payer to approve again, because a second approval could send a second payment.

To resume correctly, read the flow and act on its current state instead of repeating the last request. A request that is not valid from the current state is rejected.

## Amounts you will see

A flow reports three kinds of amount: what was requested, what was quoted, and what was delivered. They can differ, so show the one that matches the question the payer is asking.

| Amount | Fields | Meaning |
| - | - | - |
| Requested | `amount`, `currency`, `amountUsd`, `currencyTokenInfo` | The amount the flow asks for. In `deposit` mode, the payer's amount replaces it at quote time. `currencyTokenInfo` gives the symbol and decimals when the currency is `SETTLEMENT_TOKEN` |
| Quoted | `quote.fromAmount`, `quote.toAmount`, `quote.fromTokenInfo`, `quote.toTokenInfo`, `quote.fees` | What the payer sends and what the destination is expected to receive, in each token's smallest unit. For a deposit address, `fromAmount` is the amount to send |
| Delivered | `settlement.amount`, `settlement.amountUsd`, `settlement.toTokenInfo`, `settlement.toChainId`, `settlement.toToken`, `settlement.completedAt` | What actually reached your destination, in the token's smallest unit. Your server also receives it as `settledAmount` in the settlement webhook |

### Short payments depend on the mode

The mode decides what happens when less than the requested amount arrives.

* **`deposit` mode** accepts the smaller amount. The flow settles, and `settlement.amount` and `settledAmount` record what actually arrived. Show the payer that amount, and credit that amount, not the flow's `amount`.
* **`payment` mode** does not accept it. A short deposit-address payment is not settled, and the deposit provider attempts to return it to the payer's refund address. A short exchange payment fails. In this mode, `completed` means the payment was accepted in full.

A refund is never guaranteed. [Failures and refunds](https://docs.dynamic.xyz/docs/flow/failures-and-refunds.md) explains how refunds are reported and what to do when one fails.

### Limits of the delivered amount

* The `settlement` object is written only when settlement reaches `completed`. Before that, it is absent.
* `settlement.amount` and `settledAmount` are present only when the provider or the chain reports the delivered amount. Dynamic does not estimate it.
* `amountUsd` can be absent even when `amount` is present.

When the delivered amount is absent on a completed `deposit` flow, verify the settlement transaction (`settlementTxHash`) on chain before you credit an amount.

## Observing progress

Your server learns about state changes from [webhooks](https://docs.dynamic.xyz/docs/flow/webhooks.md): one event type per axis, each with the previous and new state. Your server can also read the full flow at any time with its API token.

A payer's page reads the flow again while it waits for the payment to move forward. The JavaScript and Flutter SDKs handle this for you. Use your server's view, not the page's, to decide whether to fulfill an order. [Access and data](https://docs.dynamic.xyz/docs/flow/security.md) explains why.

## Next

> [card] [Expiry and cancellation](https://docs.dynamic.xyz/docs/flow/expiry-and-cancellation.md)
>
> How long a flow and a quote last, and who can cancel.

> [card] [Failures and refunds](https://docs.dynamic.xyz/docs/flow/failures-and-refunds.md)
>
> Failure codes, refunds, and what to show the payer.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.