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

# Payment lifecycle

> Every payment status, how payments move between them, and how to track the outcome

A Payment represents one attempt to collect funds. It always moves forward
through a defined set of states and ends in exactly one terminal state.

## State diagram

```mermaid theme={null}
flowchart LR
    P["PENDING"] --> RA["REQUIRES_ACTION"]
    P --> PR["PROCESSING"]
    RA <--> PR
    PR --> S["SUCCEEDED ✓"]
    PR --> F["FAILED ✕"]
    RA --> E["EXPIRED"]
    RA --> C["CANCELED"]
```

A payment rejected before it reaches the card networks moves directly from
`PENDING` to `FAILED`.

<Note>
  A status is a snapshot of the **current state**, not a step on a progress
  bar. Hosted payment page payments move from `PENDING` directly to
  `REQUIRES_ACTION` when Flowlix receives the provider redirect URL; they do
  not go through `PROCESSING` before the customer is redirected. Direct payment
  flows may still use `PROCESSING` while the provider outcome is pending. Only
  the four terminal states (`SUCCEEDED`, `FAILED`, `EXPIRED`, `CANCELED`) are
  final. Transition history is preserved in `status_transitions`.
</Note>

## Statuses

| Status            | Terminal | Meaning                                                                                                                                                                                                                                                         |
| ----------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `PENDING`         | No       | Accepted by Flowlix, awaiting provider submission or the next lifecycle decision.                                                                                                                                                                               |
| `REQUIRES_ACTION` | No       | The customer must act — complete 3D Secure or the hosted payment page. The action is described by `next_action.reason`, and the redirect URL is in `next_action.redirect_url`. Hosted payment page payments enter this status directly after creation succeeds. |
| `PROCESSING`      | No       | Submitted to downstream payment systems; the outcome is not yet known. Flowlix synchronizes the provider result automatically — no merchant action is needed.                                                                                                   |
| `SUCCEEDED`       | Yes      | Funds were collected. The payment becomes refundable (`amount_refundable`).                                                                                                                                                                                     |
| `FAILED`          | Yes      | Declined or failed permanently. `failure_code` and `failure_message` say why.                                                                                                                                                                                   |
| `CANCELED`        | Yes      | Canceled before completion (for example, the customer canceled on the hosted page).                                                                                                                                                                             |
| `EXPIRED`         | Yes      | The customer did not complete a required action before its expiry time.                                                                                                                                                                                         |

Timestamps for each transition are exposed in `status_transitions`
(`processing_at`, `succeeded_at`, `failed_at`, ...), all as Unix timestamps in
seconds.

## Tracking the outcome

Two complementary mechanisms:

<CardGroup cols={2}>
  <Card title="Webhooks (recommended)" icon="bell" href="/guides/webhooks">
    Flowlix calls your endpoint the moment a payment reaches a new state. Best
    latency, no polling load.
  </Card>

  <Card title="Polling" icon="repeat" href="/payments-api/payments/retrieve-a-payment">
    Call `GET /v1/payments/{id}` until the status is terminal. Simple and
    dependable; use it as a fallback even when you use webhooks.
  </Card>
</CardGroup>

### Polling guidance

* Poll every **2–5 seconds** while a payment is `PROCESSING` or
  `REQUIRES_ACTION` and the customer is waiting on your page.
* When `REQUIRES_ACTION` returns a `next_action.redirect_url`, treat the URL as
  an opaque browser action URL. It can represent a hosted payment page, 3D
  Secure fingerprint collection, or a later authentication challenge. Redirect
  the customer to a new URL when it changes; if the URL is unchanged for the
  same browser session, do not redirect in a loop — keep polling and show a
  pending state.
* Switch to a slower background schedule (for example every minute, then every
  10 minutes) after the customer leaves.
* Treat only terminal statuses as final. A payment in `PROCESSING` resolves
  automatically — you never need to re-submit it.
* If a payment is still non-terminal after **24 hours**, contact support with
  the payment ID and `Request-Id`; do not create a duplicate charge.

### Reacting to each status

* `SUCCEEDED` — fulfil the order. Record `amount_refundable` if you may need
  [refunds](/guides/refunds).
* `FAILED` — read [`failure_code`](/guides/operation-failures) to decide the
  next merchant-side action.
* `EXPIRED` / `CANCELED` — the attempt is over; create a new payment if the
  customer wants to try again. Reuse your `merchant_reference` so all attempts
  for the order stay linked.

## Multiple attempts per order

One order in your system may legitimately produce several Payment objects: a
decline followed by a retry, or an abandoned hosted page followed by a new
one. Use `merchant_reference` to group attempts, and make sure at most one of
them is fulfilled — the `Idempotency-Key` header protects you against
accidental duplicates of the *same* attempt, while `merchant_reference` only
labels attempts and never blocks them.
