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

# cash_out Webhook

> Lifecycle notifications for a SPEI cash-out

## When it fires

The `cash_out` webhook type receives the lifecycle events of a transfer created via `POST /api/spei/cash-out`:

| `event`                         | `status`     | Meaning                                                                  |
| ------------------------------- | ------------ | ------------------------------------------------------------------------ |
| `transaction.cash_out.settled`  | `LIQUIDATED` | The transfer was settled on the SPEI network                             |
| `transaction.cash_out.rejected` | `REJECTED`   | The SPEI network rejected the transfer — the debited balance is returned |
| `transaction.cash_out.pending`  | `PENDING`    | Intermediate processing update                                           |

<Info>
  The **return** of an already settled cash-out (`transaction.cash_out.returned`) — when the counterparty's bank returns the transfer — is delivered on the [`refund_out`](/en/guides/webhooks/refund-out) webhook type, not on `cash_out`.
</Info>

## Payload

```json theme={"system"}
{
  "event": "transaction.cash_out.settled",
  "transactionId": "56789",
  "amount": 50000,
  "currency": "MXN",
  "status": "LIQUIDATED",
  "destinationClabe": "012180001234567890",
  "sourceClabe": null,
  "reference": "9876543",
  "voucher": "CEP20260513D4E5F6",
  "occurredAt": "2026-05-13T12:00:42.000Z"
}
```

On `status: REJECTED`, the receipt fields (`reference`, `voucher`) may be `null` — the SPEI network never confirmed the transaction.

## Headers

| Header               | Value                              |
| -------------------- | ---------------------------------- |
| `x-event-id`         | Unique event UUID (use for dedupe) |
| `X-NTXPay-Signature` | `sha256=<hmac>` of the raw body    |

## Behavior

* **At-least-once**: you may receive the same event more than once. Deduplicate by `x-event-id`.
* **Failure after success**: does not happen. A transaction never moves from `LIQUIDATED` to `REJECTED`.
* **Return**: if the counterparty returns the transfer after settlement, you receive `transaction.cash_out.returned` on the `refund_out` webhook, with the same `transactionId`.

## Expected Response

`200 OK` within 10 seconds.

## Processing

```typescript theme={"system"}
const event = JSON.parse(rawBody.toString());
if (event.event === 'transaction.cash_out.settled') {
  await markPayoutSettled(event.transactionId);
} else if (event.event === 'transaction.cash_out.rejected') {
  await markPayoutFailed(event.transactionId); // balance returned automatically
}
```

For the complete handler with HMAC validation and dedupe in Node.js, Python, Java, and Go, see [Implementation](/en/guides/webhooks/implementation).
