Webhooks
Receive signed notifications when a document or signee changes status.
What is a Bink webhook?
A webhook is an HTTP callback from Bink to your service when an event occurs. Receive document status changes without repeatedly polling the API. You can also opt in to individual signee status changes.
Supported events and lifecycle
Active webhook configurations receive document.status_changed. Enable individual signee status changes in tenant settings to also receive signee.status_changed. Independent deliveries can arrive in either order, including when the final signee completes signing.
| Status | Meaning |
|---|---|
draft | Document created, not yet sent for signing. |
in_process | Sent for signing and awaiting completion. |
pending_seal | Signing is complete but document sealing is pending. |
signed | Document signing and sealing are complete. |
- Document event data carries the previous and new document status.
- Signee statuses are
pending,signed, ordeclined. The current signing flow emitspending→signed.
Configure delivery
Configure the callback URL and secret in the tenant settings as an owner or admin. Store the secret securely when it is shown; rotating it requires updating your verifier. Use a direct HTTPS callback URL that can accept POST requests.
High-level flow
Your receiver verifies and accepts the event before returning a successful response.
- A subscribed document or signee status changes inside Bink.
- Bink sends an HTTP POST containing a JSON payload, signature, and webhook metadata headers.
- Read the exact raw request body and extract the signature header.
- Validate the signature and timestamp, then deduplicate using the event ID.
- Durably accept the event for processing and return a 2xx response promptly.
Request structure and headers
Bink sends JSON using HTTP POST. The signature below illustrates the header format; it is not a usable signature for the example payload.
POST /your-webhook-endpoint Content-Type: application/json X-Bink-Signature: t=<unix-seconds>,v1=<hmac-sha256-hex-digest> X-Bink-Webhook-Attempt: 1 X-Bink-Webhook-Event: document.status_changed X-Bink-Webhook-Id: EVENT_ID
| Header | Meaning |
|---|---|
X-Bink-Signature | t is the attempt timestamp in Unix seconds; v1 is the HMAC-SHA256 hex digest. |
X-Bink-Webhook-Attempt | Delivery attempt number, starting at 1. |
X-Bink-Webhook-Event | document.status_changed or signee.status_changed. |
X-Bink-Webhook-Id | Unique event ID, preserved across retries and matching the payload id. |
Content-Type | application/json |
Example document event
This illustrative payload reports a document moving from draft to in_process. Identifier placeholders represent values supplied by Bink in an actual event.
{
"id": "EVENT_ID",
"type": "document.status_changed",
"occurredAt": "2026-09-23T09:00:00.000Z",
"tenantId": "TENANT_ID",
"data": {
"documentId": "DOCUMENT_ID",
"oldStatus": "draft",
"newStatus": "in_process",
"changedAt": "2026-09-23T09:00:00.000Z"
}
}Example signee event
Individual signee events are opt-in. Their data also identifies the signee whose status changed.
{
"id": "EVENT_ID",
"type": "signee.status_changed",
"occurredAt": "2026-09-23T09:00:00.000Z",
"tenantId": "TENANT_ID",
"data": {
"documentId": "DOCUMENT_ID",
"signeeId": "SIGNEE_ID",
"oldStatus": "pending",
"newStatus": "signed",
"changedAt": "2026-09-23T09:00:00.000Z"
}
}Payload fields
Both event types share the same envelope. Status values in data belong to the resource identified by the event type.
| Field | Meaning |
|---|---|
id | Unique event ID. Matches X-Bink-Webhook-Id; use it for deduplication. |
type | document.status_changed or signee.status_changed. |
occurredAt | Timestamp when the event occurred. |
tenantId | Tenant identifier. |
data.documentId | Document identifier. |
data.signeeId | Signee identifier; present for signee.status_changed. |
data.oldStatus | Previous document or signee status. |
data.newStatus | New document or signee status. |
data.changedAt | Timestamp of the status change. |
Signature verification (HMAC)
Verify the exact raw body bytes before parsing JSON. Re-serializing parsed JSON can change whitespace or property order and invalidate the signature.
- Read
X-Bink-Signatureand extractt(timestamp) andv1(hex digest). Reject missing or malformed headers. - Validate timestamp freshness. The example below allows a five-minute clock tolerance.
- Build the signed payload as timestamp + "." + the raw request body.
- Compute HMAC-SHA256 using your webhook secret.
- Compare equal-length digests with a constant-time comparison.
HMAC_SHA256(secret, "<t>.<raw_body>")
Node.js verification example
Pass the raw body as a Buffer, the X-Bink-Signature header, and your securely stored webhook secret. This example rejects malformed signatures and stale timestamps before comparing digests.
import { createHmac, timingSafeEqual } from 'node:crypto';
export function verifyWebhook(rawBody, signature, secret) {
if (!Buffer.isBuffer(rawBody) || typeof signature !== 'string') return false;
const match = /^t=(\d+),v1=([a-f0-9]{64})$/.exec(signature);
if (!match) return false;
const [, timestamp, hex] = match;
const seconds = Number(timestamp);
if (!Number.isSafeInteger(seconds)) return false;
if (Math.abs(Date.now() / 1000 - seconds) > 300) return false;
const expected = createHmac('sha256', secret)
.update(timestamp + '.').update(rawBody).digest();
return timingSafeEqual(expected, Buffer.from(hex, 'hex'));
}Retry behavior
Bink makes up to three delivery attempts. The current server uses an eight-second timeout for each request. Return 2xx promptly; successful delivery stops further retries.
| Attempt | Scheduled time from dispatch start |
|---|---|
| 1 | Immediately |
| 2 | 5 seconds |
| 3 | 25 seconds |
- Attempts run sequentially. If an earlier attempt overruns the next scheduled time, the next attempt starts when the previous one finishes.
- There are no further retries after the third failed attempt.
- Use a direct callback URL. The current delivery client uses fetch’s default redirect handling; do not rely on redirects for webhook delivery.
Failure handling
Choose receiver responses deliberately: unsuccessful delivery triggers the remaining retry attempts, while a 2xx acknowledges acceptance.
| Situation | Receiver behavior |
|---|---|
| Invalid signature or timestamp | Reject with 401 or 400; do not process the event. |
| Unsupported event | Return 400 if rejecting it. If intentionally ignoring a verified event, acknowledge with 2xx to prevent retries. |
| Temporary processing or persistence failure | Return non-2xx so Bink can retry. |
| Duplicate event | Skip repeated work and return 2xx after confirming the event was already accepted. |
Quick testing
Use webhook.site to inspect test deliveries from your sandbox integration. Use test data, and remember that a request inspector is not a substitute for verifying signatures in your receiver.
- Open
webhook.siteand copy the unique URL it provides. - Configure that URL as your sandbox tenant’s webhook endpoint.
- Trigger a document status change using a sandbox document.
- Inspect the payload, signature header, event ID, and attempt number.
- Use a receiver you control to return non-2xx responses and observe retries, then return 2xx and confirm they stop.
Reliability and polling fallback
Deduplicate by event ID and make processing idempotent. Independent events may arrive out of order. Retries run in process memory, so an interruption can cause missed deliveries. For critical workflows, periodically retrieve document state through the API to reconcile missed or out-of-order events.
Security checklist
Apply these checks to your webhook receiver before enabling production delivery.
- Store the webhook secret securely and update your verifier when rotating it.
- Verify
X-Bink-Signatureagainst the exact raw body. - Validate the signature timestamp and maintain an accurate server clock.
- Use HTTPS and a direct callback URL.
- Compare digests in constant time.
- Log event IDs and attempt numbers without exposing secrets or unnecessary payload data.
- Deduplicate events and make processing idempotent.
- Accept events durably and respond quickly.
Need help?
Contact Bink support for help with webhook configuration or your integration.