Skip to main content

invoice.expired

Fired when an invoice’s expiresAt timestamp is reached and the invoice has not been fully paid.
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.

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_reasonMeaning
no_paymentNo payment was received. Customer abandoned the checkout.
underpaid_unresolvedA 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

{
  "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

Node.js
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;
}

  • invoice.settled — The happy path — full payment received and settled.
  • invoice.underpaid — Fired earlier when partial payment was received before expiry.