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

# invoice.expired

> Fired when an invoice's expiry time is reached without full payment.

# invoice.expired

Fired when an invoice's `expiresAt` timestamp is reached and the invoice has not been fully paid.

<Note>
  Manually cancelling an invoice via `POST /api/v1/invoices/:id/cancel` flips its status to `expired` but does **not** fire this webhook. If you cancel an invoice from your backend, you already know it's gone — handle the cancellation flow synchronously.
</Note>

***

## When it fires

The invoice `expiresAt` timestamp is reached and the cumulative received amount is less than the invoice total.

`data.expiry_reason` distinguishes two cases:

| `data.expiry_reason`   | Meaning                                                                                                                                                                      |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `no_payment`           | No payment was received. Customer abandoned the checkout.                                                                                                                    |
| `underpaid_unresolved` | A partial payment was received but the customer did not complete it before expiry. The partial funds remain at the deposit address — contact Settlx support to recover them. |

***

## What to do

Mark the order as failed and release any reserved inventory.

If `data.expiry_reason === 'underpaid_unresolved'`, you may want to contact the customer — they likely intended to pay and may try again. Issue a new invoice for the same amount (or the shortfall) and send them the new `paymentUrl`.

***

## Payload

```json theme={null}
{
  "event": "invoice.expired",
  "eventId": "evt_a1b2c3d4-e5f6-7890-abcd-ef1234567890_invoice.expired_1744453800000",
  "timestamp": "2026-04-12T10:30:00.000Z",
  "data": {
    "invoice": {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "amount": "49.99",
      "currency": "USD",
      "settlementCurrency": "USDT",
      "settlementChain": "polygon",
      "status": "expired",
      "createdAt": "2026-04-12T10:00:00.000Z",
      "metadata": { "orderId": "order_123" }
    },

    "expiry_reason": "no_payment"
  }
}
```

***

## Handler example

```javascript Node.js theme={null}
case 'invoice.expired': {
  const { invoice, expiry_reason } = event.data;
  const orderId = invoice.metadata?.orderId;

  await db.orders.update({
    where: { id: orderId },
    data: { paymentStatus: 'expired', expiryReason: expiry_reason },
  });

  await inventory.release(orderId);

  if (expiry_reason === 'underpaid_unresolved') {
    // Customer paid partial — they may want to retry. Send a recovery email.
    await emailService.sendRecoveryEmail(orderId);
  }

  break;
}
```

***

## Related events

* [`invoice.settled`](/webhook-events/invoice-settled) — The happy path — full payment received and settled.
* [`invoice.underpaid`](/webhook-events/invoice-underpaid) — Fired earlier when partial payment was received before expiry.
