Skip to main content

Webhooks

A webhook posts to a URL of yours when something happens in the workspace. It is the right mechanism for anything event-driven; polling the API is not.

The webhooks of a workspace

Create one under Settings → Development → Webhooks. It needs the Manager role or higher.

Setting one up

A webhook has three parts:

Target URL — where the request goes. It must be HTTPS and reachable from the internet.

Event — which change triggers it. One event per webhook; create several for several events, or use * for all of them.

Secret — generated for you, used to sign the payload.

Events

EventFires when
*Any of the events below
message.createA message arrives or is sent
message.updateA message changes
message.deleteA message is deleted
contact.createA contact is created
contact.updateA contact changes
contact.deleteA contact is deleted
conversation.createA conversation is created
conversation.updateA conversation changes
conversation.deleteA conversation is deleted
conversation.assignA conversation is assigned
conversation.closeA conversation is closed
conversation.reopenA closed conversation reopens

Verifying the signature

Each request is signed with the webhook's secret. Verify the signature before you act on a payload. Your endpoint is a public URL, and without verification anyone who finds it can post anything to it.

Compute the HMAC of the raw request body with your secret and compare it with the signature header, using a constant-time comparison.

Responding

Return a 2xx promptly. FirstReply treats anything else as a failure and retries with a backoff.

Do the actual work asynchronously: acknowledge the request, put the payload on a queue, and process it after responding. A webhook handler that calls three other services before returning will eventually time out and produce duplicates.

Handle duplicates. Retries mean an event can arrive more than once. Make your handler idempotent, keyed on the event's id.

What people build with them

Enriching contacts. On contact.create, look the person up in your own system and write their customer number and plan back as custom fields.

Notifying elsewhere. On conversation.create with high priority, post to a Slack channel.

Syncing status. On conversation.close, mark the corresponding ticket closed in whatever else your company runs.

Measuring. On every event, append to your own warehouse for reporting that goes beyond Metrics.

Debugging

Nothing arrives. Check the URL is reachable from outside your network, uses HTTPS with a valid certificate, and that the webhook is active.

Some events arrive. Each webhook carries one event. conversation.close does not fire on a new conversation; use * if you want everything.

Everything arrives twice. Your endpoint is not returning 2xx fast enough and the retry is landing. Acknowledge first, work afterwards.