> For the complete documentation index, see [llms.txt](https://docs.loomgate.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.loomgate.io/en/concepts/payments.md).

# Payments and statuses

The lifecycle of a payment, payment attempts, and when the money has actually been collected.

A **payment** (`payment_intent` in the API, with an id like `lg_pi_…`) is an amount, in one currency, that you ask a buyer to pay, together with what it pays for. Create one payment for each checkout of an order, and reuse it when the buyer tries again.

## Statuses

```mermaid
stateDiagram-v2
    [*] --> pending: payment created
    pending --> processing: buyer confirms
    processing --> succeeded: payment collected
    processing --> pending: declined, released
    pending --> canceled: canceled
    processing --> canceled: canceled
    succeeded --> [*]
    canceled --> [*]
```

| Status       | Meaning                                                                                    | You can                                                             |
| ------------ | ------------------------------------------------------------------------------------------ | ------------------------------------------------------------------- |
| `pending`    | Waiting for the buyer to pay (or to pay again after a decline)                             | Change the amount, currency and payment details; show the card form |
| `processing` | Confirmation sent, waiting for the result (for example the buyer is completing 3-D Secure) | Wait for the webhook. **The money has not been collected yet**      |
| `succeeded`  | The money has been collected. Final                                                        | Fulfill the order, refund                                           |
| `canceled`   | Canceled, can no longer be paid                                                            | Create a new payment if the buyer still wants to pay                |

{% hint style="warning" %}
Only treat an order as paid when your server receives the `payment_intent.succeeded` webhook, or when `GET /partner/v1/payment_intents/{id}` returns `status: "succeeded"`. A `processing` result in the browser does not mean the money has been collected.
{% endhint %}

### Canceled and abandoned payments

The API has no route to cancel a payment, and you do not need one: a payment the buyer abandons simply stays `pending` and costs nothing (fees are only booked when a payment `succeeded`). The payment network sets `canceled` when a payment cannot continue; you then receive the `payment_intent.canceled` webhook.

## Two ways to confirm a payment

* **Browser confirmation** (most common): `session.confirm()` in `loomgate.js` handles every step, including 3-D Secure and the release after a decline. See [Payment form](/en/integrations/browser.md).
* **Server confirmation**: the browser only creates a confirmation token, your server calls `POST /partner/v1/payment_intents/{id}/confirm` with the secret key, then the browser runs the next step if there is a `next_action`. Use this when your platform requires confirming on the server (for example WooCommerce Blocks).

## Declines and release

When a card is declined (`402 card_error`), the payment must be **released** back to `pending` before the buyer tries another card.

* In the browser flow, `loomgate.js` releases automatically.
* In the server flow, call `POST /partner/v1/payment_intents/{id}/release` (or `session.release()` in the browser). Only invite the buyer to try again once release returns `pending`.
* Only release after a confirmation that was **sent** and got a `card_error`. On a timeout, network error or 5xx, the outcome is unknown: retrieve the payment first, don't release.

## Attempt limits

To prevent card testing, every confirmation that is sent counts as one attempt, whatever the outcome:

| Limit                                                | Default | When exceeded                                                                                        |
| ---------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------- |
| Attempts per payment (`confirmation_attempts`)       | 5       | `400 payment_intent_not_pending`: nothing more is sent; the buyer must start over with a new payment |
| Attempts across the account in each 10-minute window | 50      | `429 rate_limited` with a `Retry-After` header: retry after that many seconds                        |

Loomgate sets these two numbers for your account; see the current values in the **Cài đặt** (Settings) section of the dashboard. A confirmation rejected before it is sent (missing details, suspended account…) does not count.

## When the amount changes after the form is shown

You can change the `amount` or `currency` of a `pending` payment (for example when the buyer changes the shipping fee). The card form loaded earlier is then no longer valid: the next confirmation returns `409 payment_intent_updated` and nothing is charged. `loomgate.js` reloads the form with the new amount and emits a `change` event; show the new amount and let the buyer click pay again. Changing `metadata` or the payment details does not require reloading the form.

## Suspended or unapproved accounts

* `merchant_suspended`: the account is suspended. Creating, updating, showing the form for and confirming payments are all rejected; release and refunds still work.
* `merchant_not_approved`: an account created by a reseller is awaiting approval or was rejected; it cannot accept payments yet.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.loomgate.io/en/concepts/payments.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
