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
webhookUrlsonPOST /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 URLDELETE /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, notwebhookUrl.If you do not manage terminal configuration directly, coordinate with Bead support using your
terminalIdand 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
Read the raw request body exactly as received. Do not parse or reserialize JSON before this step.
Read the
x-webhook-signatureheader and parse thetandsvalues.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.Decode
signingSecretfrom base64 to raw bytes. Use those bytes as the HMAC key.Construct the signed message by concatenating
t, a literal period, and the raw request body:message = t + "." + rawBody.Compute
HMAC-SHA256(key=decodedSecretBytes, message=message)and base64-encode the digest.Compare your computed base64 digest to
susing a constant-time comparison. Reject the request if they do not match.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
POSTContent type:
application/jsonSuccess condition: a
2xxresponse, preferably200 OKTimeout: 10 seconds per attempt
Retry behavior: exponential backoff for up to approximately 24 hours if a
2xxresponse is not returnedDelivery 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
Accept the request.
Preserve the raw body and headers.
Verify the signature.
Parse the JSON payload.
Build an idempotency key from the identifiers in the payload.
Persist or enqueue the event.
Apply business logic asynchronously if needed.
Return a
2xxresponse 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-signatureon every request where it is present.Set a terminal-level webhook at least once so a
signingSecretexists, even ifwebhookUrlsis 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
2xxresponse 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