Webhooks
Payloads
The webhook envelope, JSON encoding, realistic sample payloads, and the deleted-event rule.
Last updated Jul 14, 2026
Every webhook is a POST with exactly five top-level keys. No more,
no less.
The envelope
| Key | Type | Description |
|---|---|---|
type | string | The entity that changed: contact, company, deal, action, note, call, meeting |
reason | string | What happened: created, updated, deleted, changed_to_won, β¦ β see Events |
timestamp | integer | Unix time in seconds |
secretkey | string | The secret you configured, or empty if the in-app form left it blank |
data | object | The changed resource, nested under its entity key |
data is the resource serialized exactly like the API v3 response
for that resource β the same nested shape you get from
GET /api/v3/contacts/{id}.json, GET /api/v3/deals/{id}.json, and
so on. If you already parse API responses, you already parse webhook
payloads.
datais nested. The resource sits under its entity key:data.contact.first_name, notdata.first_name. The recordβs id isdata.contact.id,data.deal.id, and so on β matching thetypefield. Contact events also carry sibling keys (next_actions,next_action,queued_actions,most_urgent_action) alongsidedata.contact, just like the API. The one exception is deleted events, wheredatais flat:{ "id": "..." }.
Encoding
Webhooks are delivered as JSON. Content-Type: application/json, and
the body is the envelope as a JSON object:
{
"type": "note",
"reason": "created",
"timestamp": 1781426730,
"secretkey": "your-configured-secret",
"data": {
"note": {
"id": "5afc1b69d556730b580596cb",
"author": "Jane D.",
"contact_id": "5ae06ef9d55673108fe8877f",
"text": "Met Jane at the Eco Conference. Wants a quote for 40 panels.",
"date": "2026-06-10",
"linked_deal_id": "",
"linked_deal_name": "",
"attachments": [],
"created_at": "2026-06-10T08:46:10Z",
"modified_at": "2026-06-10T08:46:10Z"
}
}
}
Sample payloads
The samples below are built from the current API v3 schemas and
abridged for readability ("...": "..." marks omitted fields). The
authoritative field list for each resource is the
API reference.
contact
The contact sits under data.contact, with its actions as sibling
keys β the same shape as GET /api/v3/contacts/{id}.json:
{
"type": "contact",
"reason": "updated",
"timestamp": 1781426730,
"secretkey": "your-configured-secret",
"data": {
"contact": {
"id": "5aba31ea9007ba0f570c92d4",
"title": "Ms",
"first_name": "Jane",
"last_name": "Doe",
"job_title": "Operations Lead",
"starred": false,
"company_id": "5aba31ea9007ba0f570c92d5",
"company_name": "Acme Solar",
"emails": [{ "type": "work", "value": "jane.doe@acmesolar.example" }],
"phones": [{ "type": "work", "value": "(912) 644-1770" }],
"urls": [{ "type": "website", "value": "https://acmesolar.example" }],
"address_list": [],
"status_id": "5e31e030849d781e837b6ba1",
"status": "Prospect",
"lead_source_id": "email_web",
"lead_source": "Email or Web",
"background": "",
"owner_id": "5aba31e99007ba0f570c92a5",
"tags": ["solar", "q3-pipeline"],
"custom_fields": [],
"created_at": "2026-05-12T09:14:02Z",
"modified_at": "2026-06-10T08:45:30Z"
},
"next_actions": [
{
"id": "5aeac8789007ba56ffca92b9",
"assignee_id": "5aaa9b009007ba08c9ebaef7",
"contact_id": "5aba31ea9007ba0f570c92d4",
"text": "Email Jane the revised quote",
"status": "date",
"date": "2026-06-12",
"done": false,
"...": "..."
}
],
"next_action": { "...": "..." },
"queued_actions": [],
"most_urgent_action": { "...": "..." }
}
}
deal
A status change uses the dynamic changed_to_<status> reason β see
Events:
{
"type": "deal",
"reason": "changed_to_won",
"timestamp": 1781426741,
"secretkey": "your-configured-secret",
"data": {
"deal": {
"id": "5aaa9b059007ba08c9ebaf58",
"contact_id": "5aba31ea9007ba0f570c92d4",
"owner_id": "5aba31e99007ba0f570c12f7",
"name": "Solar panels β 40 units",
"text": "Signed PO received.",
"status": "won",
"last_stage": 75,
"close_date": "2026-06-10",
"amount": 4500.0,
"months": 1,
"total_amount": 4500.0,
"cost": 0.0,
"date": "2026-05-20",
"author": "Jane D.",
"contact_info": {
"contact_name": "Jane Doe",
"company": "Acme Solar",
"...": "..."
},
"created_at": "2026-05-20T16:10:45Z",
"modified_at": "2026-06-10T08:45:41Z",
"...": "..."
}
}
}
The stage and date keys depend on the dealβs status:
- Pending deals carry
stageandexpected_close_date. - Won and lost deals carry
last_stage(the stage the deal closed from) andclose_dateinstead.
action
Completed actions serialize with status: "done", done: true,
and a done_at date. There is no date key on a completed action:
{
"type": "action",
"reason": "completed",
"timestamp": 1781426755,
"secretkey": "your-configured-secret",
"data": {
"action": {
"id": "5aeac8789007ba56ffca92b9",
"assignee_id": "5aaa9b009007ba08c9ebaef7",
"contact_id": "5aba31ea9007ba0f570c92d4",
"text": "Email Jane the revised quote",
"status": "done",
"done": true,
"done_at": "2026-06-10",
"created_at": "2026-06-09T11:52:09Z",
"modified_at": "2026-06-10T08:45:55Z"
}
}
}
note
{
"type": "note",
"reason": "created",
"timestamp": 1781426770,
"secretkey": "your-configured-secret",
"data": {
"note": {
"id": "5afc1b69d556730b580596cb",
"author": "Jane D.",
"contact_id": "5aba31ea9007ba0f570c92d4",
"text": "Met Jane at the Eco Conference. Wants a quote for 40 panels.",
"date": "2026-06-10",
"linked_deal_id": "",
"linked_deal_name": "",
"attachments": [],
"created_at": "2026-06-10T08:46:10Z",
"modified_at": "2026-06-10T08:46:10Z"
}
}
}
When no deal is linked, linked_deal_id is "" β an empty string,
never null.
call, meeting, and company events nest the same way:
data.call, data.meeting, data.company.
Deleted events
When reason is deleted, data contains only the id, flat β
no entity key:
{
"type": "contact",
"reason": "deleted",
"timestamp": 1781426790,
"secretkey": "your-configured-secret",
"data": {
"id": "5aba31ea9007ba0f570c92d4"
}
}
This is always the case β it doesnβt matter whether the delete is
still undoable. If you need the recordβs last state, keep your
own copy keyed by id, or treat the delete as a tombstone.