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

# Underpayments and overpayments

What happens when a customer sends too little, too much, too late or on the wrong network.

Crypto customers sometimes send too little, too much, too late or on the wrong network. Checkout catches each case, and the payment tells you what happened.

## Underpaid

A transfer that falls short by no more than your underpayment tolerance counts as paid in full. The tolerance is 0.5% unless you change it in Settings, under Checkout, and covers things like a wallet taking its network fee out of the amount.

When less than that arrives, the payment becomes `underpaid` and you receive `payment.underpaid`. Checkout shows the customer exactly what's left and keeps watching the same address at the same rate for a fresh quote window, 15 minutes by default, so most customers simply send the rest. Then you have three choices.

- underpaid (payment.underpaid) → Customer sends the rest (same address and rate)
- underpaid (payment.underpaid) → Request the rest (a checkout for what's left)
- underpaid (payment.underpaid) → Accept what arrived (counts it as paid)
- Customer sends the rest (same address and rate) → succeeded (payment.succeeded)
- Request the rest (a checkout for what's left) → succeeded (payment.succeeded)
- Accept what arrived (counts it as paid) → succeeded (payment.succeeded)

- Wait: if the customer sends the rest in time, the payment succeeds as usual.
- Request the rest once the quote has expired. See below.
- Accept what arrived, if the shortfall doesn't matter to you. See below.

## Request the rest

[`POST /payments/{id}/request-remainder`](https://developer.402pay.co/api/payments/request-remainder.md) opens a checkout for exactly what's left, in the same coin and network, attached to the original payment, and returns a `url` to send the customer. When the rest arrives, the original payment succeeds; no second payment is made.

- It works once the quote has expired, on a link payment or one you created through the API. While the quote is live, the customer can still send the rest to the same address, so it returns 409 `remainder_unavailable`.
- Asking again while the remainder's checkout is open returns the same checkout, and the request needs an `Idempotency-Key`.

Request the rest, cURL:

```bash
curl -X POST "https://dash.402pay.co/api/v1/payments/pmt_uYs2XjkL1jGJt44v/request-remainder" \
  -H "Authorization: Bearer $PAY402_SECRET_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

Request the rest, Node.js:

```js
const response = await fetch("https://dash.402pay.co/api/v1/payments/pmt_uYs2XjkL1jGJt44v/request-remainder", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.PAY402_SECRET_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
  },
});
const { data } = await response.json();
```

Request the rest, Python:

```python
import os
import uuid

import requests

response = requests.post(
    "https://dash.402pay.co/api/v1/payments/pmt_uYs2XjkL1jGJt44v/request-remainder",
    headers={
        "Authorization": f"Bearer {os.environ['PAY402_SECRET_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
)
data = response.json()["data"]
```

## Accept what arrived

[`POST /payments/{id}/accept`](https://developer.402pay.co/api/payments/accept.md) makes an `underpaid` or `needs_review` payment `succeeded` with what arrived. `amount_received` shows it, `reporting` counts it, and the timeline gains an `accepted` event. You receive `payment.succeeded`, so fulfill the order as usual, or decide on your side whether a part payment is enough.

## Overpaid

When more than the amount due arrives, the whole amount lands in your wallet, the payment succeeds, and you also receive `payment.overpaid`. `method.overpaid_amount` shows the excess, which you can send back from your wallet if you choose.

## Needs review

Some transfers need your decision: the payment becomes `needs_review` and you receive `payment.needs_review`. The reason is on the payment's checkout, in `review_reason`: read it with [`GET /checkouts/{id}`](https://developer.402pay.co/api/checkouts/retrieve.md), using the payment's `checkout_id`.

| review_reason | What happened |
| --- | --- |
| `late` | The transfer arrived after the checkout expired, so the rate it was quoted at no longer held. |
| `wrong_network` | The transfer arrived on another EVM network at the same address. The checkout's `crypto.detected_network` and the payment's `method.network` name it. |
| `claimed` | The customer said they paid, with a transaction hash, after the checkout closed. |

- A late transfer still reaches your wallet, but the rate it was quoted at no longer holds. Accept it, or return the funds to the customer.
- Every EVM network shares your address, so a transfer on another EVM network still lands in your wallet, on that network. Transfers on unrelated networks can't reach you, which is why checkout names the network so clearly.
- A claim is only the customer's word: check the transaction hash in the timeline's `claimed` event on a block explorer before you accept it.

> Rehearse each case before launch on a simulated business with [simulated outcomes](https://developer.402pay.co/testing.md#simulate).
