> ## 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.failed

> An invoice failed in a non-recoverable way. Currently fires for wrong-token resolutions.

# invoice.failed

Fired when an invoice reaches a non-recoverable failure state. The `data.failure_reason` field tells you exactly what happened.

Today this event fires for **wrong-token deposit resolutions** — when a customer paid the deposit address using a different token than the invoice expected, and a Settlx admin processes the resolution. Future failure modes will also use this event with new `failure_reason` values, so handle the field as an extensible enum.

***

## Failure reasons

| `data.failure_reason`   | Meaning                                                                                                                                                                       |
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `wrong_token_refunded`  | The customer paid the wrong token; Settlx returned the funds to the sender's address. The merchant did **not** receive any payment.                                           |
| `wrong_token_forwarded` | The customer paid the wrong token; Settlx forwarded the funds to the merchant's wallet **in the original (mismatched) currency** instead of the expected settlement currency. |

<Warning>
  For `wrong_token_forwarded`, the funds in your wallet are in the **wrong currency** — not your usual settlement currency. Your accounting must handle this case explicitly.
</Warning>

***

## What to do

Branch on `data.failure_reason`:

### `wrong_token_refunded`

* Mark the order as **failed** in your system
* Notify the customer that their payment was returned
* Release any reserved inventory
* Do **not** fulfil the order — no funds arrived

### `wrong_token_forwarded`

* The funds **did** arrive in your merchant wallet, in whatever asset the customer actually sent
* Decide whether you accept this as fulfilment of the order
* Use `data.withdrawalAmount` and `data.withdrawalCurrency` to record what was received

***

## Payload

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

    "failure_reason": "wrong_token_forwarded",

    "withdrawalTxHash":     "0x9f4c3a8b7e6d5f4c3a8b7e6d5f4c3a8b7e6d5f4c3a8b7e6d5f4c3a8b7e6d5f4c",
    "withdrawalDestination":"0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb1",
    "withdrawalAmount":     "49.99",
    "withdrawalCurrency":   "USDT",
    "withdrawalChain":      "ethereum"
  }
}
```

| Field                        | Description                                                                                                   |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------- |
| `data.failure_reason`        | What went wrong and how it was handled                                                                        |
| `data.withdrawalTxHash`      | On-chain hash of the refund/forward transaction                                                               |
| `data.withdrawalDestination` | Address that received the funds (sender for refund, merchant wallet for forward)                              |
| `data.withdrawalAmount`      | Amount that was moved                                                                                         |
| `data.withdrawalCurrency`    | Currency of the moved funds — for wrong-token cases this is the **wrong** token, not your settlement currency |
| `data.withdrawalChain`       | Chain the withdrawal occurred on                                                                              |

***

## Handler example

```javascript Node.js theme={null}
app.post('/webhooks/settlx', express.raw({ type: 'application/json' }), async (req, res) => {
  verifySignature(req);
  const event = JSON.parse(req.body);

  if (event.event === 'invoice.failed') {
    const { invoice, failure_reason, withdrawalAmount, withdrawalCurrency, withdrawalTxHash } = event.data;
    const orderId = invoice.metadata?.orderId;

    if (failure_reason === 'wrong_token_refunded') {
      await db.orders.update(orderId, {
        status: 'failed',
        failureReason: 'wrong_token_refunded',
        refundTxHash: withdrawalTxHash,
      });
      await notifyCustomer(invoice.metadata?.customerId, {
        message: 'Your payment was returned because it was sent in the wrong token.',
      });
    }

    if (failure_reason === 'wrong_token_forwarded') {
      await db.orders.update(orderId, {
        status: 'received_alt_currency',
        receivedAmount: withdrawalAmount,
        receivedCurrency: withdrawalCurrency,
        settlementTxHash: withdrawalTxHash,
      });
      // Decide whether to fulfil based on your business rules
      await reviewAlternateCurrencyOrder(orderId);
    }
  }

  res.status(200).json({ received: true });
});
```

***

## Future failure reasons

`failure_reason` is designed as an extensible enum. New values may be added over time without introducing new event types. Always handle unknown values gracefully — log them and either treat as a generic failure or escalate to manual review.

***

## Related events

* [`invoice.settled`](/webhook-events/invoice-settled) — The happy path. If you receive `invoice.failed` you will not receive `invoice.settled` for the same invoice.
* [`invoice.expired`](/webhook-events/invoice-expired) — Different failure mode (timeout, no wrong-token involved).
