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

# Event reference

> Every webhook event, when it fires, and what to do with it.

## Lifecycle

```mermaid theme={null}
flowchart LR
    A[payment_intent_created] --> B[payment_submitted]
    B --> C[payment_confirmed]
    B --> D[payment_failed]
    A --> E[payment_expired]
    A -.-> F[payment_blocked]
    C --> G[payment_claimed]
    style C fill:#064e3b,stroke:#10B981,color:#fff
```

Only one of these should release goods.

## Events

<AccordionGroup>
  <Accordion title="payment_confirmed — fulfil here" icon="circle-check" defaultOpen>
    The payment reached finality and is irreversible. **This is your fulfilment trigger.**

    Connect rail: the deposit transaction reached required confirmations. Deposit rail: the inbound transfer confirmed *and* our sweep into your pool confirmed.

    ```json theme={null}
    {
      "id": "payment_confirmed_a1b2c3d4",
      "event": "payment_confirmed",
      "created_at": "2026-08-09T14:32:11.204Z",
      "data": {
        "paymentId": "…",
        "orderId": "your-order-ref",
        "amount": "49000000",
        "token": "EURC",
        "chainId": 8453,
        "txHash": "0x…"
      }
    }
    ```

    <Note>
      `amount` is in token base units. On most chains these tokens use 6 decimals, so `49000000` is 49.00 — but decimals vary by chain (BNB Chain is 18). Scale by the payment's `tokenDecimals` rather than assuming 6.
    </Note>
  </Accordion>

  <Accordion title="payment_intent_created" icon="file-circle-plus">
    A customer started checkout and an intent exists. Nothing has been paid.

    Useful for abandonment analytics. Do not treat as a sale.
  </Accordion>

  <Accordion title="payment_submitted" icon="paper-plane">
    A transaction was broadcast but has not reached finality.

    Good for a "confirming…" state. **Not** safe to ship on — it can still fail or be reorganised. [Finality](/concepts/finality).
  </Accordion>

  <Accordion title="payment_failed" icon="circle-xmark">
    The attempt failed. Nothing was taken from the customer.

    Show a retry option.
  </Accordion>

  <Accordion title="payment_expired" icon="hourglass-end">
    The quote window elapsed with no payment.

    <Warning>
      Expiry locks the price, not the address. A customer can still pay afterwards and the money still arrives. Don't cancel the order irreversibly on this event — mark it lapsed and wait.
    </Warning>
  </Accordion>

  <Accordion title="payment_blocked" icon="ban">
    The payment was refused by a compliance check. Deliberately non-specific, to avoid coaching evasion.

    Only fires if you've enabled payer screening. [Sanctions](/compliance/sanctions).
  </Accordion>

  <Accordion title="payment_claimed" icon="hand-holding-dollar">
    A payout completed and funds moved to your payout address.

    Useful for reconciliation and accounting. Not customer-facing.
  </Accordion>
</AccordionGroup>

## Handling them

```javascript theme={null}
switch (event.event) {
  case "payment_confirmed":
    await fulfilOrder(event.data.orderId);   // the only one that ships
    break;

  case "payment_submitted":
    await markConfirming(event.data.orderId);
    break;

  case "payment_failed":
    await markFailed(event.data.orderId);
    break;

  case "payment_expired":
    await markLapsed(event.data.orderId);    // NOT cancelled — late payment is possible
    break;

  case "payment_claimed":
    await recordPayout(event.data);
    break;

  default:
    break;                                   // ignore unknown events
}
```

<Tip>
  Ignore events you don't recognise rather than erroring. New event types can be added, and a handler that 500s on an unknown type will look like an outage to our retry logic.
</Tip>

## Deposit-rail statuses

The deposit rail carries richer per-invoice states than the events above. They surface in your dashboard and the status API:

| Status              | Meaning                                     |
| ------------------- | ------------------------------------------- |
| `waiting`           | Address issued, nothing received            |
| `confirming`        | Funds seen, awaiting confirmations          |
| `paid`              | Correct amount confirmed                    |
| `underpaid`         | Less than expected — see `confirmed_amount` |
| `overpaid`          | More than expected                          |
| `wrong_token`       | A token you haven't enabled                 |
| `swept`             | Moved into your pool                        |
| `expired`           | Quote lapsed, nothing received              |
| `expired_paid_late` | Paid after expiry — funds arrived and count |
| `held_sanctioned`   | Frozen pending compliance review            |

[What to do about each](/money/edge-cases).
