Browse documentation

Webhooks

Subscribe a URL to deal events and NeoKivo POSTs a signed payload as they happen. The event catalog, delivery and retry behavior, and what happens when a webhook stops working.

Updated 2026-07-06

A webhook is a URL you register in Settings that NeoKivo calls when a deal changes. It's the fastest way to react to pipeline events from outside NeoKivo — no polling required.

The event catalog

EventFires when
deal.createdA new deal is added
deal.stage_changedA deal moves to a different pipeline stage
deal.wonA deal is marked won
deal.lostA deal is marked lost

These four are the whole public vocabulary today. Reopening a deal (won or lost back to open) does not emit anything.

Subscribe to a webhook

  1. 1Open Settings → Integrations. Only the workspace owner can create, delete, or re-enable a webhook.
  2. 2Under Webhooks, set up a subscription: an https:// URL, one or more events, and a format — plain JSON, or a Slack-compatible message for an incoming-webhook channel URL.
  3. 3Copy the signing secret. It starts with nk_whsec_ and is shown only once.

URLs must be https — the payload carries deal data and is worth protecting in transit. Up to 10 subscriptions per workspace.

Delivery semantics

  • Every delivery is signed with HMAC-SHA256 over the raw body — see verify webhook signatures for the exact scheme and a verifier.
  • Each attempt times out after 10 seconds. Any 2xx response counts as success; anything else, a timeout, or a redirect counts as a failure (redirects are never followed).
  • A failed delivery retries with backoff: roughly 30s, 1m, 2m, 4m, 8m, 16m, 32m, then 64m — 8 retries, about 2 hours of attempts, before that delivery is exhausted.
  • Delivery is at-least-once, not exactly-once: if a batch of deliveries is interrupted partway through, the retry re-sends to subscriptions that already got a copy.
  • Deliveries are not ordered. Sort by occurredAt in the payload, not by arrival time.

X-Neokivo-Delivery identifies a delivery attempt, not the underlying event — a duplicate delivery of the same event carries a different id. If you need idempotency, key on the payload's content instead: (event, data.deal.id, occurredAt).

Disabled webhooks

After 20 consecutive deliveries exhaust every retry with no success in between — roughly 180 failed requests over several days to a truly dead endpoint — the subscription disables itself and you get a webhook.disabled notification, addressed to the webhook's creator if they're still a member, or to every workspace owner if not.

The same thing happens immediately, independent of that counter, if the subscription's creator leaves the workspace: deliveries stop rather than falling back to workspace-wide visibility. This is the same fail-closed rule API keys and the MCP server follow.

Re-enabling a disabled webhook is owner-only, from Settings. It resets the failure count, and makes the re-enabling owner the subscription's new creator — deliveries from then on are scoped to what they can see.

The payload

Every delivery is a versioned envelope: the event name, when it happened, the workspace, and the deal — plus the from/to stage names on a stage change. See verify webhook signatures for the full envelope shape, a real sample, and how to check the signature before you trust the body.

Spotted something out of date? Email hello@neokivo.com.