For the complete documentation index, see llms.txt. This page is also available as Markdown.

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 configured at the terminal level. The following endpoints manage the terminal's webhook URL:

  • PUT /Terminals/{id}/webhook — set or update the terminal webhook URL

  • DELETE /Terminals/{id}/webhook — remove the terminal webhook URL

Authentication

Use your admin API key in the X-Api-Key header for terminal webhook management. These endpoints do not accept a terminal payments API key. Using a terminal payments API key will return 403 Forbidden.

Request headers

<table><thead><tr><th width="170">Header</th><th>Value</th></tr></thead><tbody><tr><td><code>X-Api-Key</code></td><td><code>{adminApiKey}</code></td></tr><tr><td><code>Content-Type</code></td><td><code>application/json</code></td></tr><tr><td><code>Accept</code></td><td><code>application/json</code></td></tr></tbody></table>

Request body

<table><thead><tr><th width="80">Field</th><th width="126">Type</th><th width="141">Required</th><th>Description</th></tr></thead><tbody><tr><td><code>url</code></td><td>string (URI)</td><td>Yes</td><td>Fully qualified HTTPS URL where terminal-level payment status events should be delivered. Maximum 512 characters.</td></tr></tbody></table>

Example request

Example response

Store signingSecret securely. Use it to verify the x-webhook-signature header on all incoming webhook deliveries for this terminal. Treat it like a password and do not log it or expose it in client-side code.

Notes

  • Use an HTTPS endpoint.

  • The request body field is url, not webhookUrl.

  • If you do not manage terminal configuration directly, coordinate with Bead support using your terminalId and the desired webhook URL.

Signature header

The x-webhook-signature header is included on both terminal-level webhook deliveries and per-payment deliveries sent to webhookUrls. Both delivery paths use the same terminal's signingSecret and the same signing logic — but each individual delivery is signed with its own fresh timestamp, so the signature value differs per delivery even when the JSON body sent to multiple destinations is identical.

This depends on the terminal having a signingSecret configured. A terminal only gets a signingSecret once you've called PUT /Terminals/{id}/webhook on it at least once. If a terminal has never had a webhook configured this way, it has no signingSecret, and any webhookUrls deliveries for payments on that terminal are sent without an x-webhook-signature header — silently, with no error or warning surfaced anywhere. If your integration relies on webhookUrls rather than the terminal's own default URL, set a terminal-level webhook at least once to establish the secret before you depend on signature verification.

Example:

<table><thead><tr><th width="98">Field</th><th>Description</th></tr></thead><tbody><tr><td><code>t</code></td><td>Unix epoch timestamp in <strong>milliseconds</strong> when Bead generated the event</td></tr><tr><td><code>s</code></td><td><strong>Base64-encoded</strong> HMAC-SHA256 digest of the signed message <code>t + "." + rawBody</code>, computed using the decoded bytes of the terminal's <code>signingSecret</code></td></tr></tbody></table>

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. Do not parse or reserialize JSON before this step.

  2. Read the x-webhook-signature header and parse the t and s values.

  3. Validate the timestamp by confirming t (in milliseconds) is within your allowed freshness window. A 5-minute skew limit is recommended to prevent replay attacks.

  4. Decode signingSecret from base64 to raw bytes. Use those bytes as the HMAC key.

  5. Construct the signed message by concatenating t, a literal period, and the raw request body: message = t + "." + rawBody.

  6. Compute HMAC-SHA256(key=decodedSecretBytes, message=message) and base64-encode the digest.

  7. Compare your computed base64 digest to s using a constant-time comparison. Reject the request if they do not match.

  8. Only then parse and process the JSON body.

For a full code example, see How do I verify that a webhook really came from Bead?

Delivery mechanics

  • Method: HTTP POST

  • Content type: application/json

  • Success condition: a 2xx response, preferably 200 OK

  • Timeout: 10 seconds per attempt

  • Retry behavior: exponential backoff for up to approximately 24 hours if a 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 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 in 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, with receivedTime optionally included for debugging.

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, and 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 where it is present.

  • Set a terminal-level webhook at least once so a signingSecret exists, even if webhookUrls is your main delivery path — otherwise those deliveries arrive unsigned.

  • Treat the signing secret like a password.

  • Reject malformed or unsigned requests.

  • Reject 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 allowlisting 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:

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.

Last updated