# Simulate Invoice Payment

> Move a sandbox invoice through a payment outcome and test the same lifecycle and webhooks as a confirmed on-chain transfer.

`POST /v1/sandbox/invoices/:invoice_id/simulate-payment`

:::endpoint
POST /v1/sandbox/invoices/:invoice_id/simulate-payment
:::

**API key:** `Payment` · **Environment:** Sandbox only

Simulates a confirmed payment without moving real funds. The invoice must belong to the authenticated merchant and the sandbox environment. A production key is rejected.

## Request body

`stage` is required and accepts exactly one of:

- `paid` — pay the remaining amount;
- `overpaid` — pay the remaining amount plus a random positive excess;
- `underpay` — pay a random positive part of the remaining amount. If multiple payments are allowed, calls can repeat and payments accumulate; otherwise, the invoice closes as `underpaid`;
- `cancel` — cancel an invoice that is still eligible for cancellation.
- `paid_late` — pay the full expected amount after the deadline. An invoice with no money yet (`awaiting_payment`) closes as `expired`, a partly paid one (`underpaid_waiting`) closes as `underpaid`, and one already closed as `expired` or `underpaid` keeps that status. `payment.paid` counts only what arrived before the deadline, as in production, where a late payment is credited to your balance separately from the invoice. The invoice gains the late-payment mark, and the only webhook is `invoice.paid_late`.

For `underpay`, if token precision or tolerance leaves no positive partial payment below the auto-confirm threshold, the request is rejected without changing the invoice. Status webhooks are sent only when the status changes.

```json
{
  "stage": "paid"
}
```

The server derives every simulated amount from the invoice. Clients never calculate settlement amounts.

## Response (200 OK)

Returns the updated invoice resource and emits the same lifecycle webhook events as the corresponding real outcome. See [Get Invoice](/docs/invoices/get.md) for the response fields.
