Envelope (version 1)
Every delivery — custom webhook endpoints, Zapier REST Hooks, and replays — uses the same shape. Configure endpoints in Dashboard → Settings → Integrations → Webhooks.
Example payload
{
"id": "550e8400-e29b-41d4-a716-446655440099",
"type": "submission.created",
"version": 1,
"occurredAt": "2026-06-11T10:00:00.000Z",
"workspaceId": "550e8400-e29b-41d4-a716-446655440000",
"object": {
"type": "submission",
"id": "550e8400-e29b-41d4-a716-446655440001"
},
"data": {
"fullName": "Jane Doe",
"email": "[email protected]",
"phone": "+15551234567",
"message": "I would like a demo.",
"formId": "00000000-0000-0000-0000-000000000001",
"formName": "Contact us",
"contactId": "00000000-0000-0000-0000-000000000002",
"leadId": "00000000-0000-0000-0000-000000000003",
"conversationId": "00000000-0000-0000-0000-000000000004",
"fieldValues": {
"company": "Example Co",
"budget": "5k-10k"
}
}
}HTTP headers
| Header | Value |
|---|---|
| Content-Type | application/json |
| User-Agent | Jambo-Webhooks/1.0 |
| X-Jambo-Signature | v1=<hex hmac-sha256> |
| X-Jambo-Timestamp | <unix seconds> |
| X-Jambo-Event-Type | submission.created |
| X-Jambo-Event-Id | <envelope id> |
The signature covers {timestamp}.{rawBody} using HMAC-SHA256 and your endpoint signing secret. Reject requests older than five minutes.
Verify signatures (Node.js)
import crypto from 'node:crypto'
function verifyJamboWebhook(req, secret) {
const timestamp = req.headers['x-jambo-timestamp']
const signature = req.headers['x-jambo-signature']
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false
const expected =
'v1=' +
crypto.createHmac('sha256', secret).update(`${timestamp}.${req.rawBody}`).digest('hex')
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(expected))
}Event catalog
Subscribe to one or more event types per endpoint. REST Hooks use the same vocabulary via eventTypes on POST /integrations/zapier/hooks.
submission.createdForm submission receivedA public form was submitted. Fires once per submission, after the contact and lead are saved. `fieldValues` contains mapped custom field values keyed by mapping target.
{ "data": { "fullName": "Jane Doe", "email": "[email protected]", "phone": "+15551234567", "message": "I would like a demo.", "formId": "00000000-0000-0000-0000-000000000001", "formName": "Contact us", "contactId": "00000000-0000-0000-0000-000000000002", "leadId": "00000000-0000-0000-0000-000000000003", "conversationId": "00000000-0000-0000-0000-000000000004", "fieldValues": { "company": "Example Co", "budget": "5k-10k" } } }contact.createdContact createdA new contact record was created — from a form submission, inbound email, or manual entry.
{ "data": { "contactId": "00000000-0000-0000-0000-000000000002", "fullName": "Jane Doe", "email": "[email protected]", "phone": "+15551234567", "company": "Example Co" } }contact.updatedContact updatedAn existing contact was edited or enriched via import.
{ "data": { "contactId": "00000000-0000-0000-0000-000000000002", "fullName": "Jane Doe", "email": "[email protected]", "phone": "+15551234567", "company": "Example Co" } }message.receivedInbound message receivedA channel-agnostic inbound message (web_form, email, or future whatsapp). `message` mirrors `contentText`; contact fields are included when the message is linked to a contact.
{ "data": { "messageId": "00000000-0000-0000-0000-000000000005", "conversationId": "00000000-0000-0000-0000-000000000004", "contactId": "00000000-0000-0000-0000-000000000002", "leadId": "00000000-0000-0000-0000-000000000003", "channelType": "web_form", "contentText": "Hi, following up on my enquiry.", "message": "Hi, following up on my enquiry.", "email": "[email protected]", "fullName": "Jane Doe", "phone": "+15551234567" } }message.sentOutbound message sentAn outbound reply was delivered from the inbox or agent (team member or AI). Includes `authorType`, `authorLabel`, optional `subject`, and contact enrichment when available.
{ "data": { "messageId": "00000000-0000-0000-0000-000000000005", "conversationId": "00000000-0000-0000-0000-000000000004", "contactId": "00000000-0000-0000-0000-000000000002", "leadId": "00000000-0000-0000-0000-000000000003", "channelType": "email", "contentText": "Thanks for reaching out — happy to help with pricing.", "message": "Thanks for reaching out — happy to help with pricing.", "authorType": "ai", "authorLabel": "AI agent", "subject": "Re: Demo request", "email": "[email protected]", "fullName": "Jane Doe", "phone": "+15551234567" } }task.createdTask createdA new task was created — manually or by the inbound agent. Includes the full task snapshot plus a preformatted `message` note for tools that ingest plain text.
{ "data": { "taskId": "00000000-0000-0000-0000-000000000010", "title": "Follow up with Jane", "description": "Send the rate card and confirm availability.", "status": "open", "priority": "medium", "source": "agent", "actionType": "open_conversation", "href": "/dashboard/inbox/00000000-0000-0000-0000-000000000004", "assigneeMemberId": "00000000-0000-0000-0000-000000000011", "assigneeEmail": "[email protected]", "createdByMemberId": "00000000-0000-0000-0000-000000000011", "conversationId": "00000000-0000-0000-0000-000000000004", "leadId": "00000000-0000-0000-0000-000000000003", "contactId": "00000000-0000-0000-0000-000000000002", "contactName": "Jane Doe", "messageId": null, "email": "[email protected]", "fullName": "Jane Doe", "phone": "+15551234567", "dueAt": "2026-06-15T09:00:00.000Z", "completedAt": null, "createdAt": "2026-06-11T10:00:00.000Z", "updatedAt": "2026-06-12T10:05:00.000Z", "message": "[Task created] Follow up with Jane\nStatus: open\n/dashboard/inbox/00000000-0000-0000-0000-000000000004\n\nSend the rate card and confirm availability." } }task.updatedTask updatedAn existing task was edited (title, status, assignee, due date, etc.).
{ "data": { "taskId": "00000000-0000-0000-0000-000000000010", "title": "Follow up with Jane", "description": "Send the rate card and confirm availability.", "status": "done", "priority": "medium", "source": "agent", "actionType": "open_conversation", "href": "/dashboard/inbox/00000000-0000-0000-0000-000000000004", "assigneeMemberId": "00000000-0000-0000-0000-000000000011", "assigneeEmail": "[email protected]", "createdByMemberId": "00000000-0000-0000-0000-000000000011", "conversationId": "00000000-0000-0000-0000-000000000004", "leadId": "00000000-0000-0000-0000-000000000003", "contactId": "00000000-0000-0000-0000-000000000002", "contactName": "Jane Doe", "messageId": null, "email": "[email protected]", "fullName": "Jane Doe", "phone": "+15551234567", "dueAt": "2026-06-15T09:00:00.000Z", "completedAt": "2026-06-12T10:05:00.000Z", "createdAt": "2026-06-11T10:00:00.000Z", "updatedAt": "2026-06-12T10:05:00.000Z", "message": "[Task updated] Follow up with Jane\nStatus: done\n/dashboard/inbox/00000000-0000-0000-0000-000000000004\n\nSend the rate card and confirm availability." } }task.deletedTask deletedA task was permanently deleted. The payload is the last snapshot before deletion.
{ "data": { "taskId": "00000000-0000-0000-0000-000000000010", "title": "Follow up with Jane", "description": "Send the rate card and confirm availability.", "status": "open", "priority": "medium", "source": "agent", "actionType": "open_conversation", "href": "/dashboard/inbox/00000000-0000-0000-0000-000000000004", "assigneeMemberId": "00000000-0000-0000-0000-000000000011", "assigneeEmail": "[email protected]", "createdByMemberId": "00000000-0000-0000-0000-000000000011", "conversationId": "00000000-0000-0000-0000-000000000004", "leadId": "00000000-0000-0000-0000-000000000003", "contactId": "00000000-0000-0000-0000-000000000002", "contactName": "Jane Doe", "messageId": null, "email": "[email protected]", "fullName": "Jane Doe", "phone": "+15551234567", "dueAt": "2026-06-15T09:00:00.000Z", "completedAt": null, "createdAt": "2026-06-11T10:00:00.000Z", "updatedAt": "2026-06-12T10:05:00.000Z", "message": "[Task deleted] Follow up with Jane\nStatus: open\n/dashboard/inbox/00000000-0000-0000-0000-000000000004\n\nSend the rate card and confirm availability." } }
Delivery semantics
- Deduplication: use envelope
id— we may deliver more than once. - Retries: network errors, timeouts, HTTP 5xx, and 429 are retried with backoff (up to six attempts: 1m → 5m → 15m → 15m → 15m). Other 4xx responses are terminal.
- Auto-pause: after five consecutive abandoned deliveries, an endpoint is paused until you resume it in settings.
- Test events: use the “Send test” button in webhook settings for a
test.pingconnectivity check (not part of normal subscriptions).