Subscribe to CRM events, verify signatures, and debug failed deliveries.
TL;DR — Pick events, give us an HTTPS URL, we POST JSON there every time something changes. Re-send failed deliveries from the UI or through MCP. Verify signatures with HMAC-SHA256 over the raw body.
Webhooks turn your CRM into the source of truth your other tools listen to. No polling, no stale data.
Common uses:
UI: Company → Webhooks → New.
MCP: create_webhook with url, events[], optional description, secret, enabled.
{
"url": "https://hooks.example.com/customermates",
"events": ["contact.created", "contact.updated", "deal.updated"],
"secret": "use-a-random-string-from-a-password-manager",
"enabled": true
}The URL must be HTTPS. HTTP is rejected.
Every delivery is a POST with Content-Type: application/json:
{
"event": "contact.updated",
"data": {
"userId": "...",
"companyId": "...",
"entityId": "...",
"payload": {
"contact": { "id": "...", "firstName": "Max", "lastName": "Mustermann" },
"changes": {
"organizationIds": { "previous": [], "current": ["..."] }
}
}
},
"timestamp": "2026-04-22T10:00:00.000Z"
}The changes record is only present on *.updated events. It names every field that actually moved, with previous and current values.
See webhook events for the full event list and payload shapes.
If you set a secret, every outgoing request includes:
X-Webhook-Signature: <hex>Where <hex> is HMAC-SHA256(secret, rawRequestBody), lowercase hex, no prefix. Recompute on your side and compare in constant time.
Node.js example:
import crypto from "crypto";
function verify(rawBody: string, received: string, secret: string) {
const expected = crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}Every delivery is recorded. See them in the UI (Company → Webhook Deliveries) or through list_webhook_deliveries.
A delivery is considered failed if the HTTP status is outside the 2xx range or the request times out.
Retry a failed delivery through the UI or resend_webhook_delivery with the delivery id. A new delivery record is created; the original is unchanged.
Customermates does not automatically retry failed deliveries. If your receiver is down, trigger retries from the UI or pipe list_webhook_deliveries through a monitoring script.
Deliveries are not strictly ordered across events. Two contact.updated events a millisecond apart can arrive out of order. Use the timestamp in the payload to resolve, or treat deliveries as idempotent messages keyed by entityId.
list_webhook_deliveries tool supports searchTerm on url and event name.