Receiving events (webhooks)
A webhook sends a POST to your URL each time one of the events it subscribes to happens. Owners
and admins create them in Settings → Webhooks. Zapier (“Webhooks by Zapier → Catch Hook”),
Make and n8n can receive them directly.
Events
Section titled “Events”| Type | When | data |
|---|---|---|
lead.received |
A lead arrives through POST /leads/intake |
lead, person, deal |
person.created |
A contact is created | person |
deal.created |
A deal is created | deal |
deal.owner_changed |
A deal gets a new owner (deal.owner; from is the previous one) |
deal, from |
deal.stage_changed |
A deal changes stage | deal, from, to |
deal.won |
A deal reaches a won stage (after deal.stage_changed) |
deal |
deal.lost |
A deal reaches a lost stage (after deal.stage_changed) |
deal |
unit.status_changed |
A unit becomes available, reserved or sold | unit, from, to, deal |
kit.viewed |
A client opens a shared sales kit (at most every 30 min) | link, collection, deal |
Records are snapshots taken when the event happened. They include names, emails, the unit’s place in
the catalog (path) and unit type and a url to open it in the CRM, so most receivers don’t need to call back.
Request
Section titled “Request”POST /your/endpointcontent-type: application/jsonwebhook-id: 01a1a2cb-a581-753c-97bd-3371de23fbc7webhook-timestamp: 1793732617webhook-signature: v1,K5oZfzN95Z9UVu1EsfQmfVNQhnkZ2pj9o9NDN/H/pI4=
{ "id": "8da75d2a-d5be-4037-9d9e-9311adcebe6b", "type": "deal.won", "timestamp": "2026-11-03T19:03:37.600Z", "organizationId": "01a18e82-8246-7e43-82aa-5c246b073f08", "data": { "deal": { "publicId": "DL-87", "title": "A-101 · Ana López", "amount": "3250000.00", "currency": "MXN", "stage": { "name": "Won", "kind": "won" }, "owner": { "name": "Carlos", "email": "carlos@example.com" }, "person": { "name": "Ana López", "email": "ana@example.com", "phone": "+52 998 123 4567" }, "units": [{ "name": "A-101", "path": ["Cancún", "Arbolada", "Tower A"], "inventoryStatus": "sold" }], "url": "https://crm.example.com/deals/…" } }}Answer with any 2xx within 10 seconds. Anything else, or no answer, is retried with exponential
backoff for several hours. Each attempt and the response you returned show up in the webhook’s
delivery log, where a delivery can also be sent again.
Verifying the signature
Section titled “Verifying the signature”Requests follow Standard Webhooks, so any of its libraries can
check them with the webhook’s signing secret (whsec_…):
import { Webhook } from "standardwebhooks"
const webhook = new Webhook(process.env.CRM_WEBHOOK_SECRET)// Throws if the signature is wrong or the timestamp is older than 5 minutes.const event = webhook.verify(rawBody, request.headers)Verify the raw body, before parsing it. Rotating the secret in the CRM invalidates the old one right away.
Duplicates and order
Section titled “Duplicates and order”A delivery that is retried or sent again keeps its webhook-id. Store the ids you’ve processed and
skip repeats. Deliveries can arrive out of order; use timestamp when order matters.