> For the complete index of the 402pay docs, see [llms.txt](https://developer.402pay.co/llms.txt).

# Hosted checkout

Everything between choosing how to pay and the receipt, on one hosted page.

Your server and hosted checkout

Recommended

- **Code needed**: One API call and a webhook handler
- **Time**: An afternoon
- **Customization**: Amount, reference, metadata, redirects and expiry on every payment
- **Best for**: Stores and apps with their own orders

Every link, and every payment you create through the API, has a hosted checkout at its `url`. It handles everything between the customer choosing how to pay and their receipt, on any screen. A payment made through a link has no `url` of its own: the customer paid on the link's.

## What the customer sees

- The customer picks card or crypto, then a coin and network from the ones you accept.
- A card goes straight to the card payment page, in a new tab or, on a phone, the same one, and checkout waits on it. See [card payments](https://developer.402pay.co/guides/card-payments.md#checkout-flow).
- Each crypto checkout pays to a fresh address in your wallet, at a rate that holds while it's open, so every transfer matches one payment.
- Checkout spots the transfer and follows it until it has the confirmations it needs.
- A short transfer gets a request for exactly what's left, and an overpayment lands in your wallet in full. See [underpayments](https://developer.402pay.co/guides/underpayments.md).
- When it's paid, the customer gets a receipt, or goes to your `success_url`.

## What checkout handles, and what you own

| Checkout handles | You own |
| --- | --- |
| Coin, network and card choice | Which coins, networks and rails you accept, in Settings |
| Fresh addresses and locked rates | The price, currency and reference of each payment |
| Detection, confirmations and short transfers | Fulfilling the order when the webhook arrives |
| The receipt | Your success and cancel pages |

## Checkout statuses

| Status | Meaning |
| --- | --- |
| `open` | Waiting for the customer to pay. |
| `awaiting_customer` | Waiting for the customer to finish paying by card. |
| `processing` | A card payment is being approved. |
| `confirming` | The transfer arrived and is collecting confirmations. |
| `underpaid` | Part of the amount arrived. The customer can send the rest. |
| `completed` | Paid in full. |
| `expired` | Nothing arrived in time, or the transfer landed on a sibling quote, which `replaced_by` names. |
| `canceled` | The customer or you canceled it. `canceled_by` says which. |
| `failed` | The payment couldn't be completed. |
| `needs_review` | Funds arrived but need your decision, such as after expiry or on another network. |

## Build your own

The hosted page runs on public endpoints you can call yourself. [Create a checkout](https://developer.402pay.co/api/checkouts/create.md) with the payment's code, the last part of its `url`, then [read it](https://developer.402pay.co/api/checkouts/retrieve.md) every few seconds until its `status` is `completed`. When the customer goes back to choose again, supersede the old checkout and pass its ID as `replaces` on the new one, so the same choice keeps the same quote and address. If the transfer then lands on the quote the customer left, that quote is the one being paid and the new one closes with `replaced_by` naming it: read that one instead, and never offer a new quote for a checkout closed that way.

For a card, send the customer to the checkout's `card.payment_url` as it is. Browsers only let a tab open during the customer's tap, so open a blank one as they press your button, before you create the checkout, then point it at the URL; where it can't open, go there in the same tab. The card payment page returns the customer to the checkout's page on the hosted checkout.
