# Webhook Event Reference

## Webhook Event Reference

Webhook notifications let your backend react to changes without polling. This page is the shared operational reference for Bead webhook delivery.

Use this page for:

* delivery behavior and retries
* signature verification
* idempotent processing
* ordering and replay safety
* production operating guidance

Use the product-specific webhook page for:

* setup and registration steps
* payload fields and examples
* event types or status meanings
* product-specific business handling

### What this page does and does not define

This page defines the shared operational model for webhook handling.

This page does **not** define a single canonical payload schema for every webhook family. Payload shape is product-specific. Do not assume a shared cross-product envelope unless the relevant product page explicitly documents one.

### Where events go

#### Payments

Bead supports two payment webhook delivery paths:

* **Terminal default webhook**\
  Configured at the terminal level. Applies to all payments created by that terminal.
* **Per-payment webhook URLs**\
  Supplied through `webhookUrls` on `POST /Payments/crypto`. Applies only to that individual payment.

When both are present, Bead fans out the same payment event to the terminal webhook and to each URL listed in `webhookUrls`.

#### Other webhook families

Other product areas may define their own webhook registration path and event selection model. Use the product-specific webhook page for setup details.

### Configure the terminal default webhook

Payment webhooks are typically configured at the terminal level using OAuth-authenticated terminal endpoints:

* `PUT /Terminals/{id}/webhook`
* `GET /Terminals/{id}/webhook`
* `DELETE /Terminals/{id}/webhook`

Minimal example:

```http
PUT /Terminals/{id}/webhook
Authorization: Bearer {access_token}
Content-Type: application/json
Accept: application/json
```

```json
{
  "webhookUrl": "https://example.com/bead/webhooks"
}
```

Notes:

* Use an HTTPS endpoint.
* Terminal management endpoints use OAuth, not the Payments API key.
* If you do not manage terminal configuration directly, coordinate with Bead support using the `terminalId` and desired webhook URL.

### Signature header

Webhook requests include the `x-webhook-signature` header.

Example:

```
x-webhook-signature: t=1752067200,s=9d6309b739a8e5b87e3c2b8d1d4fbc17e5e3c7f3c5b5a9d3e...
```

Where:

* `t` is a Unix epoch timestamp in seconds
* `s` is the HMAC-SHA256 signature of the raw request body using the webhook signing secret

Always verify the signature against the **raw request body** before parsing or processing JSON.

### Signature verification flow

1. Read the raw request body exactly as received.
2. Read the `x-webhook-signature` header.
3. Parse the `t` and `s` values.
4. Recompute the HMAC-SHA256 signature using your signing secret and the raw body.
5. Compare your computed signature to the received signature using a constant-time comparison.
6. Optionally reject stale timestamps outside your allowed freshness window.
7. Only then parse and process the JSON body.

### Delivery mechanics

* **Method:** HTTP `POST`
* **Content type:** `application/json`
* **Success condition:** a successful `2xx` response, preferably `200 OK`
* **Timeout:** 10 seconds per attempt
* **Retry behavior:** exponential backoff for up to about 24 hours if a successful `2xx` response is not returned
* **Delivery model:** at least once
* **Ordering:** do not assume perfect ordering
* **One event per change:** webhook families such as Payments send one event per status change

If your endpoint does not return a successful `2xx` response quickly, Bead may retry the same event.

### Recommended processing model

1. Accept the request.
2. Preserve the raw body and headers.
3. Verify the signature.
4. Parse the JSON payload.
5. Build an idempotency key from the identifiers provided by the payload.
6. Persist or enqueue the event.
7. Apply business logic asynchronously if needed.
8. Return a `2xx` response quickly.

### Idempotency and duplicate handling

Treat webhook delivery as at least once.

If a webhook family does not provide a dedicated `eventId`, derive idempotency from the identifiers in the payload.

For payment webhooks, a practical idempotency key is:

* `trackingId`
* `statusCode`
* `receivedTime` when present

Do not treat duplicate deliveries as errors. They are a normal part of retry-safe webhook delivery.

### Ordering and state convergence

Do not assume events arrive in perfect order.

Your handler should:

* compare the incoming event to your current known state
* ignore older or duplicate state transitions when appropriate
* converge on the latest valid state

If you need to confirm the latest current state, call the relevant read endpoint for that product area.

### Security checklist

* Use HTTPS webhook endpoints.
* Verify `x-webhook-signature` on every request.
* Treat the signing secret like a password.
* Reject malformed or unsigned requests.
* Consider rejecting stale timestamps to reduce replay risk.
* Avoid logging secrets or full sensitive headers.
* Keep development, staging, and production webhook URLs separate.
* Do not rely on source IP allow listing alone. Signature verification should be your primary trust control.

### Operational checklist

* Return a `2xx` response quickly.
* Queue or persist work before heavy downstream processing.
* Instrument request logging and delivery failures.
* Track retry volume and error rates.
* Build idempotent consumers.
* Test both happy-path and non-happy-path events in sandbox.

### Product-specific pages

Use the product-area webhook page for payload fields, examples, and business handling:

* [Payment Webhooks](https://developers.bead.xyz/payments/payment-webhooks)
* [Webhooks for Application Events](https://developers.bead.xyz/onboarding/webhooks-for-application-events)

### Forward compatibility

New webhook families may add dedicated event types, wrapper envelopes, or event IDs.

Always validate against the product-specific documentation for that webhook family rather than assuming the same body shape across all products.
