POST request to the URL you register, carrying a signed JSON payload with everything you need to update your CRM, trigger a sales alert, or kick off an automation.
Supported Events
Create a Webhook
Register a new webhook endpoint byPOSTing to /v1/webhooks with your destination URL and the list of events you want to subscribe to.
secret_prefix is a preview only — it shows a truncated portion of your signing secret, not the full value. Retrieve the full signing key with the endpoint below.webhooks:write scope; listing them and fetching the signing key requires webhooks:read.
Payload Structure
Every webhook deliveryPOSTs the event’s full JSON payload directly as the request body — there’s no {"event": ..., "data": ...} envelope wrapping it. The event type is instead carried in the X-Knock-Event request header. Every payload includes a product_slug identifying which tenant the event fired for (see the Parent/Child Fan-in section below).
Beyond that, the shape is specific to each event: account.identified and contact.identified carry the full account/contact record, with an id you can re-fetch via GET /v1/accounts/{id} or GET /v1/contacts/{id}. score.changed carries its own id plus a company_lead_id or person_lead_id — there’s no GET /v1/scores/{id}, so use that id to look the current score back up via GET /v1/scores?account_id= / ?contact_id=. play.triggered carries play_id/contact_ids rather than a top-level id. signal.detected nests its record (including its own id) under data. tenant.limit_reached and tenant.limit_approaching describe a threshold being crossed rather than a single fetchable record, so neither has an id at all.
signal.detected is the one exception: its own payload happens to include event and data keys as part of its normal shape (see its tab below) — that’s a property of that specific event, not a general envelope every event is wrapped in.
Here is a real sample payload for each event type:
workflow.triggered is a deprecated alias of play.triggered — Knock2 dispatches it with the exact same payload shown in the play.triggered tab above (play_id/play_name are simply aliased as workflow_id/workflow_name). Existing subscriptions keep receiving it; don’t subscribe new integrations to it.Verifying Signatures
Knock2 signs every webhook payload with HMAC-SHA256 and delivers the signature in theX-Knock-Signature request header. Always verify the signature before processing the payload to ensure the request genuinely came from Knock2.
Verification is a standard HMAC-SHA256 check over the raw request body bytes (not a parsed/re-serialized object):
Getting Your Signing Key
Thesecret you pass to the snippets above is retrieved with GET /v1/webhooks/{webhook_id}/secret (requires the webhooks:read scope):
Unlike your API key, the signing key is never stored — it’s re-derived from the subscription ID on every request, so you can fetch it again at any time. There’s no “shown only once” restriction, and nothing is invalidated by requesting it more than once.
List Webhooks
Retrieve all registered webhook subscriptions for your account:This endpoint is not paginated —
GET /v1/webhooks returns all active subscriptions for your tenant in a single response, without has_more/next_cursor.Delete a Webhook
Remove a webhook subscription by sending aDELETE request with the webhook ID:
204 No Content with an empty body. Knock2 stops delivering events to that URL immediately.
Webhook endpoint URLs must use HTTPS. Plain HTTP URLs are rejected at registration time to ensure your payload data is encrypted in transit. If you’re testing locally, use a tunneling tool such as ngrok to simulate deliveries safely.
Parent/Child Fan-in
A subscription you create with your own (parent) API key automatically covers events fired for every one of your child tenants too — you don’t need to register a separate subscription per child, and tenants created after the subscription already exists are covered from the moment they’re created. Every delivery includes aproduct_slug field so you can tell which tenant an event actually came from.
If a child tenant also has its own subscription for the same event type, both fire — duplicate delivery across a parent-level and child-level subscription is the accepted default, since deliveries are already dedupable by X-Knock-Delivery-Id.
Delivery and Retries
Deliveries are at-least-once — design your handler to be idempotent (dedupe on the event payload’sid). If your endpoint doesn’t respond successfully, Knock2 retries with the following backoff schedule: 1 minute, 5 minutes, 30 minutes, then 2 hours after the initial attempt. After the 5th attempt fails, the delivery is marked dead-lettered and no further retries occur.