for developers
https://sandbox-api.bink.fi
EVENTS

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.

Supported events and lifecycle
StatusMeaning
draftDocument created, not yet sent for signing.
in_processSent for signing and awaiting completion.
pending_sealSigning is complete but document sealing is pending.
signedDocument signing and sealing are complete.
  • Document event data carries the previous and new document status.
  • Signee statuses are pending, signed, or declined. The current signing flow emits pendingsigned.

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.

  1. A subscribed document or signee status changes inside Bink.
  2. Bink sends an HTTP POST containing a JSON payload, signature, and webhook metadata headers.
  3. Read the exact raw request body and extract the signature header.
  4. Validate the signature and timestamp, then deduplicate using the event ID.
  5. 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
Request structure and headers
HeaderMeaning
X-Bink-Signaturet is the attempt timestamp in Unix seconds; v1 is the HMAC-SHA256 hex digest.
X-Bink-Webhook-AttemptDelivery attempt number, starting at 1.
X-Bink-Webhook-Eventdocument.status_changed or signee.status_changed.
X-Bink-Webhook-IdUnique event ID, preserved across retries and matching the payload id.
Content-Typeapplication/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.

Payload fields
FieldMeaning
idUnique event ID. Matches X-Bink-Webhook-Id; use it for deduplication.
typedocument.status_changed or signee.status_changed.
occurredAtTimestamp when the event occurred.
tenantIdTenant identifier.
data.documentIdDocument identifier.
data.signeeIdSignee identifier; present for signee.status_changed.
data.oldStatusPrevious document or signee status.
data.newStatusNew document or signee status.
data.changedAtTimestamp 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.

  1. Read X-Bink-Signature and extract t (timestamp) and v1 (hex digest). Reject missing or malformed headers.
  2. Validate timestamp freshness. The example below allows a five-minute clock tolerance.
  3. Build the signed payload as timestamp + "." + the raw request body.
  4. Compute HMAC-SHA256 using your webhook secret.
  5. 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.

Retry behavior
AttemptScheduled time from dispatch start
1Immediately
25 seconds
325 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.

Failure handling
SituationReceiver behavior
Invalid signature or timestampReject with 401 or 400; do not process the event.
Unsupported eventReturn 400 if rejecting it. If intentionally ignoring a verified event, acknowledge with 2xx to prevent retries.
Temporary processing or persistence failureReturn non-2xx so Bink can retry.
Duplicate eventSkip 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.

  1. Open webhook.site and copy the unique URL it provides.
  2. Configure that URL as your sandbox tenant’s webhook endpoint.
  3. Trigger a document status change using a sandbox document.
  4. Inspect the payload, signature header, event ID, and attempt number.
  5. 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-Signature against 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.

Try it in the API console →

Authorize sandbox

Sent directly to https://sandbox-api.bink.fi as X-Api-Key. Kept in memory until you refresh.