Event catalog
All webhook events emitted by Billium, with full payload shapes.
Billium delivers 15 event types across two categories: invoice events, which track the high-level lifecycle of a charge, and payment events, which track the on-chain transactions that settle that charge.
Each event is classified as durable or best-effort — this determines the delivery guarantee. Durable events are retried until delivered (at-least-once); best-effort events are dispatched once and may be dropped if Billium experiences a failure in-flight. See Delivery guarantees for the full model.
As a rule of thumb: drive your business logic off durable events (invoice.paid, invoice.expired, etc.) and treat best-effort events (invoice.updated, payment.created, payment.updated) as UI hints only.
Invoice events
invoice.created
Fired when a new invoice is created.
{
"event": "invoice.created",
"id": "evt_...",
"data": {
"invoiceId": "inv_...",
"merchantId": "mer_...",
"amount": 49.99,
"cryptocurrency": "USDT",
"network": "ethereum",
"status": "AWAITING_PAYMENT",
"paymentAddress": "0xAbCdEf...",
"expectedCryptoAmount": "49.952341",
"expiresAt": "2025-03-15T05:00:00.000Z",
"metadata": {}
},
"timestamp": "2025-03-15T04:00:00.000Z"
}invoice.updated
Fired whenever the invoice status changes. Includes the new status.
{
"event": "invoice.updated",
"id": "evt_...",
"data": {
"invoiceId": "inv_...",
"merchantId": "mer_...",
"status": "PENDING_CONFIRMATION",
"metadata": {}
},
"timestamp": "2025-03-15T04:08:00.000Z"
}invoice.paid
Fired when the invoice is fully confirmed on-chain and the received amount matches exactly.
{
"event": "invoice.paid",
"id": "evt_...",
"data": {
"invoiceId": "inv_...",
"merchantId": "mer_...",
"paymentId": "pay_...",
"amount": 49.99,
"cryptocurrency": "USDT",
"network": "ethereum",
"receivedCryptoAmount": "49.952341",
"txHash": "0xabcdef1234...",
"metadata": {}
},
"timestamp": "2025-03-15T04:12:00.000Z"
}This is the event you care about most — use it to fulfill orders, unlock content, or update your database.
invoice.underpaid
Fired when the transaction is confirmed but the received amount is less than expected.
{
"event": "invoice.underpaid",
"id": "evt_...",
"data": {
"invoiceId": "inv_...",
"merchantId": "mer_...",
"paymentId": "pay_...",
"expectedCryptoAmount": "49.952341",
"receivedCryptoAmount": "40.000000",
"txHash": "0xabcdef1234...",
"metadata": {}
},
"timestamp": "2025-03-15T04:12:00.000Z"
}invoice.overpaid
Fired when the transaction is confirmed but the received amount is more than expected.
{
"event": "invoice.overpaid",
"id": "evt_...",
"data": {
"invoiceId": "inv_...",
"merchantId": "mer_...",
"paymentId": "pay_...",
"expectedCryptoAmount": "49.952341",
"receivedCryptoAmount": "75.000000",
"txHash": "0xabcdef1234...",
"metadata": {}
},
"timestamp": "2025-03-15T04:12:00.000Z"
}invoice.expired
Fired when an invoice reaches its expiresAt time without a confirmed payment.
{
"event": "invoice.expired",
"id": "evt_...",
"data": {
"invoiceId": "inv_...",
"merchantId": "mer_...",
"metadata": {}
},
"timestamp": "2026-04-12T05:00:00.000Z"
}invoice.cancelled
Fired when a merchant cancels an invoice via POST /invoices/{id}/cancel or the dashboard. Only invoices in non-terminal states can be cancelled.
{
"event": "invoice.cancelled",
"id": "evt_...",
"data": {
"invoiceId": "inv_...",
"merchantId": "mer_...",
"metadata": {}
},
"timestamp": "2026-04-12T04:30:00.000Z"
}Payment events
payment.detected
Fired as soon as a matching transaction is seen on-chain, before it accumulates enough confirmations. Useful for showing the customer a "payment detected, waiting for confirmation" message.
{
"event": "payment.detected",
"id": "evt_...",
"data": {
"paymentId": "pay_...",
"invoiceId": "inv_...",
"merchantId": "mer_...",
"txHash": "0xabcdef1234...",
"receivedCryptoAmount": "49.952341",
"confirmations": 1,
"requiredConfirmations": 12
},
"timestamp": "2025-03-15T04:08:00.000Z"
}payment.confirmed
Fired each time the confirmation count increases, until the required threshold is reached.
{
"event": "payment.confirmed",
"id": "evt_...",
"data": {
"paymentId": "pay_...",
"invoiceId": "inv_...",
"merchantId": "mer_...",
"txHash": "0xabcdef1234...",
"confirmations": 6,
"requiredConfirmations": 12
},
"timestamp": "2026-04-12T04:10:00.000Z"
}payment.paid
Fired when a single payment settles with the exact expected amount. This is the per-payment counterpart of invoice.paid — subscribe to it if you need transaction-level granularity (e.g. an invoice that's paid by multiple transactions). Most integrations only need invoice.paid.
{
"event": "payment.paid",
"id": "evt_...",
"data": {
"paymentId": "pay_...",
"invoiceId": "inv_...",
"merchantId": "mer_...",
"txHash": "0xabcdef1234...",
"amount": "49.952341",
"currency": "USDT"
},
"timestamp": "2026-04-12T04:12:00.000Z"
}payment.underpaid
Fired when a single payment confirms with less than the expected amount. The invoice may still reach invoice.paid later if further payments arrive — always check the invoice status before acting on a payment.underpaid.
payment.overpaid
Fired when a single payment confirms with more than the expected amount. As with payment.underpaid, this is a per-payment signal — use invoice.overpaid for the aggregate view.
payment.expired
Fired when a detected payment never reaches the required confirmation count before the invoice's expiry window closes.
{
"event": "payment.expired",
"id": "evt_...",
"data": {
"paymentId": "pay_...",
"invoiceId": "inv_...",
"merchantId": "mer_..."
},
"timestamp": "2026-04-12T05:00:00.000Z"
}payment.created
Fired when a new payment row is inserted (customer initiated the checkout). Best-effort — use it for UI hints, not for critical logic.
payment.updated
Fired on low-level payment field changes — received amount, confirmation count, expiry, tx hash. Fires frequently and is best-effort. Most integrations should prefer payment.confirmed (durable) for confirmation updates.
Event summary
| Event | Trigger | Delivery | Terminal? |
|---|---|---|---|
invoice.created | Invoice created via API | Best-effort | No |
invoice.updated | Any status change | Best-effort | No |
invoice.paid | Confirmed, exact amount | Durable | Yes |
invoice.underpaid | Confirmed, short amount | Durable | Yes |
invoice.overpaid | Confirmed, excess amount | Durable | Yes |
invoice.expired | Deadline passed without payment | Durable | Yes |
invoice.cancelled | Merchant cancelled via API or dashboard | Durable | Yes |
payment.created | New payment row inserted | Best-effort | No |
payment.updated | Payment row updated | Best-effort | No |
payment.detected | Tx seen on-chain | Durable | No |
payment.confirmed | Each new confirmation | Durable | No |
payment.paid | Payment reached terminal paid state | Durable | Yes |
payment.underpaid | Payment confirmed under expected | Durable | Yes |
payment.overpaid | Payment confirmed over expected | Durable | Yes |
payment.expired | Payment abandoned before confirming | Durable | Yes |
Subscribing to all events in a category
When creating a webhook, pass the wildcard event invoice.* or payment.* to subscribe to every event in that category without listing them individually.