Webhooks
Bindly can POST signed events to your endpoint the moment things happen in your workspace — an insured finishes an application, a submission goes out to a market, a signature envelope completes. Webhooks are the push complement to the workspace API: use the event to learn that something happened, then pull whatever you need (including the filled PDFs) with the API.
-
In the app, open Integrations → Webhooks and add your endpoint URL. Pick the events you want; every endpoint gets its own signing secret (
whsec_…), shown once. -
Click Send test event. Bindly POSTs a
webhook.testdelivery so you can verify your handler and signature check end to end. -
Return any
2xxquickly. Do slow work after responding — deliveries time out at 10 seconds per attempt.
If you use Zapier instead of your own endpoint, the Bindly Zapier app (available from Integrations → Zapier in the app) subscribes to the same events for you — no endpoint or signature handling required.
Events
Section titled “Events”| Event | Fires when | Payload highlights |
|---|---|---|
fill_session.completed |
An application reaches complete — the intake finished and the forms rendered | session_id, insured_name, state, form_keys, completed_at |
submission.sent |
A submission email leaves the workspace (Gmail, Microsoft, or a connected market) | session_id, to, cc, subject, form_keys, provider, sent_at |
esign.completed |
A signature envelope completes | session_id, envelope_id, completed_at |
Delivery format
Section titled “Delivery format”Every delivery is a JSON POST with a fixed top-level shape:
{ "id": "5f0c4d0e-…", "event": "fill_session.completed", "created_at": "2026-08-21T18:03:11.482Z", "data": { "session_id": "fa697249-…", "org_id": "91d91b20-…", "insured_name": "Bluebonnet Handyman Services LLC", "state": "TX", "status": "complete", "form_keys": ["ACORD_125"], "completed_at": "2026-08-21T18:02:58.113Z" }}Headers on every delivery:
| Header | Value |
|---|---|
X-Bindly-Event |
The event name |
X-Bindly-Delivery |
The delivery id (same as body id) |
X-Bindly-Signature |
sha256=<hex HMAC-SHA256 of the raw body> |
Verifying signatures
Section titled “Verifying signatures”The signature is an HMAC-SHA256 of the raw request body bytes, keyed with
your endpoint’s whsec_… secret, hex-encoded, prefixed with sha256=.
Always verify against the raw body — parsing and re-serializing the JSON can
reorder keys and break verification.
import { createHmac, timingSafeEqual } from "node:crypto";
function verifyBindlySignature(rawBody, header, secret) { const expected = "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex"); const a = Buffer.from(header ?? ""); const b = Buffer.from(expected); return a.length === b.length && timingSafeEqual(a, b);}
// Express: capture the raw body, then verify before trusting the payload.app.post("/bindly-webhook", express.raw({ type: "application/json" }), (req, res) => { if (!verifyBindlySignature(req.body, req.get("X-Bindly-Signature"), process.env.BINDLY_WHSEC)) { return res.status(401).end(); } const delivery = JSON.parse(req.body); res.status(200).end(); // respond fast, work after handle(delivery);});import hashlib, hmac
def verify_bindly_signature(raw_body: bytes, header: str, secret: str) -> bool: expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest() return hmac.compare_digest(header or "", expected)Retries and idempotency
Section titled “Retries and idempotency”- Each delivery makes up to 3 attempts (immediately, then after 2s and
5s) with a 10-second timeout per attempt. Any
2xxcounts as delivered; anything else after the last attempt is recorded as failed. - Failed deliveries are visible (with the response status and error) on the endpoint’s delivery log in Integrations → Webhooks. Bindly does not re-drive failed deliveries across runs in v1 — treat webhooks as notifications and reconcile with the API if you need guarantees.
- Deliveries are idempotent per event: internal retries of the same
completion round, or races between two observers of the same envelope,
produce at most one delivery per endpoint per natural key
(
session_id + completed_atfor completions,envelope_idfor e-sign). DuplicateX-Bindly-Deliveryids never occur; if your handler retries internally, key your own idempotency on the deliveryid.
After the event: pulling the artifacts
Section titled “After the event: pulling the artifacts”The payload is deliberately light. Typical follow-ups with the workspace API:
GET /org/sessions/{id}— the session’s current state and answers.GET /org/sessions/{id}/forms/{form_key}/pdf— a rendered, filled PDF (one call per entry inform_keys).GET /org/sessions/{id}/risk-summary— the narrative risk summary.