Outbound Webhooks
Outbound webhooks send real-time HTTP POST notifications to external URLs when events occur in the system. Use them to integrate with automation platforms like n8n, Zapier, Make, or custom middleware.
Overview
When an event occurs (such as a contact being created, an extension being updated, or a message being sent), the system sends an HTTP POST request to each webhook URL subscribed to that event. The payload includes the event type, a timestamp, and the relevant data.
Outbound webhooks are configured under Integrations > Outbound Webhooks in the tenant settings.
Creating a Webhook
Click Add to create a new webhook. Each webhook has:
- Name - a descriptive label for the webhook
- URL - the destination endpoint that will receive the POST requests
- Secret - an optional shared secret used to sign payloads with HMAC-SHA256 so consumers can verify authenticity
- Active - enable or disable delivery without deleting the webhook
- Events - select which events trigger this webhook, organized into three categories
Event Categories
Events are grouped into three categories, each with its own selector:
CRM Events
- Contact - created, updated, deleted
- Account - created, updated, deleted
- Lead - created, updated, deleted, converted to contact
- List - created, updated, deleted
- Activity - created
- Deal - created, updated, stage changed
- Task - created, completed
- Campaign - created, status changed
Wildcard subscriptions are supported (e.g., contact.* matches all contact events).
Configuration Events
- Extension - created, updated, deleted
- DID - created, updated, deleted
- Trunk - created, updated, deleted
- Queue - created, updated, deleted
- Hunt Group - created, updated, deleted
- IVR - created, updated, deleted
- Administrator - created, updated, deleted
Communications Events
- Call - completed, missed
- Voicemail - received
- WhatsApp - message received, message sent
- SMS - message received, message sent
Payload Format
Each webhook delivery sends a JSON payload:
{ "event": "extension.created", "timestamp": 1710700000, "data": { "name": "john", "extension": "1001", "first_name": "John", "last_name": "Doe" }}The following HTTP headers are included:
| Header | Description |
|---|---|
Content-Type | application/json |
X-Webhook-Event | The event name (e.g., contact.created) |
X-Webhook-Timestamp | Unix timestamp of the delivery |
X-Webhook-Signature | HMAC-SHA256 signature (if a secret is configured) |
Verifying Signatures
If a secret is configured, the system signs each payload using HMAC-SHA256. To verify:
- Concatenate the timestamp and the raw request body with a
.separator - Compute HMAC-SHA256 using the shared secret
- Compare the result with the
X-Webhook-Signatureheader
Example in Python:
import hmac, hashlib
def verify_webhook(payload_body, timestamp, signature, secret): expected = hmac.new( secret.encode(), f"{timestamp}.{payload_body}".encode(), hashlib.sha256 ).hexdigest() return hmac.compare_digest(expected, signature)Testing Webhooks
Click the Test Webhook button on the webhook grid to send a test event (webhook.test) to the configured URL. This verifies connectivity and lets you inspect the payload format at the receiving end.
The test delivery is logged in the delivery log just like regular events.
Trying it without a real receiver
You do not need to stand up a real HTTP service to validate that webhook delivery is working. Free public request inspectors are convenient for ad-hoc testing:
- webhook.site - generates a unique URL on load and shows every incoming request in real time, including headers and body. Paste the URL into the URL field, save, then click Test Webhook and switch back to the webhook.site tab to inspect the request.
- requestbin.com - similar to webhook.site with a different UI.
https://httpbin.org/post- returns 200 and echoes the request back in the response body. Useful when you want to confirm the test handler reports a clean success.
About redirects (HTTP 301 / 302)
Webhook delivery does not follow HTTP redirects on POST. If your receiver returns a 301 or 302, the test will report the redirect status as a failure rather than re-POSTing to the redirect target. This is intentional - silent redirect-following is a security and reliability hazard for webhook receivers. If you see a 301 in the test result, the most common causes are:
- The URL was typed with
http://and the host now requireshttps:// - The URL is missing or has an extra trailing slash that the server canonicalizes
- The URL points at a vanity host that redirects to a
www.or other canonical host
Run curl -i -X POST '<your-url>' and look at the Location: response header to see the URL the receiver wants you to use, then save that as the webhook URL.
Delivery Log
Click the Deliveries badge on the webhook grid to open the delivery log. The log shows:
- Time - when the delivery was attempted
- Event - which event triggered the delivery
- Status - HTTP status code (green for 2xx, red for errors)
- Payload - the JSON payload that was sent
- Response - the response body from the receiving server
The delivery log retains the most recent 200 entries per webhook.
Retry Behavior
Webhook delivery uses a 5-second timeout. If the destination does not respond or returns a non-2xx status code, the failure is logged and the webhook’s failure counter is incremented. The last_triggered and last_status_code fields on the webhook record are updated after each delivery attempt.
Permissions
Access to outbound webhooks requires the outbound_webhooks permission, which is included in the Global Admin, System Admin, Tenant Admin, and Multi-Tenant Admin roles by default.
Worked example: notify n8n when a CRM contact is created
Goal: every time a contact is added in this tenant, an n8n workflow receives the details and posts them to Slack.
- Get a receiving URL. In n8n, add a Webhook node set to
POSTand copy its production URL (for a quick dry run you can use a webhook.site URL instead). - Create the webhook. Under Integrations > Outbound Webhooks, click Add. Set Name
n8n - new contacts, paste the URL, and set a Secret (for example a 32-character random string). Leave Active on. - Subscribe to the right event. In the CRM Events selector, choose Contact > created - or, if you also want updates and deletes later, the
contact.*wildcard. Save. - Test before going live. Click Test Webhook. n8n’s node shows an incoming request with headers
X-Webhook-Event: webhook.testandX-Webhook-Signature. Confirm the body shape matches the payload format above. - Verify the signature in the workflow. In n8n, add a Function/Code step that recomputes HMAC-SHA256 over
`${timestamp}.${rawBody}`using your secret and compares it toX-Webhook-Signature(same logic as the Python snippet above). Reject anything that does not match, then continue to the Slack node. - Go live. Create a contact in the CRM. Within a second the webhook fires
contact.createdwith the new contact indata; n8n verifies the signature and posts to Slack. If nothing arrives, open the Deliveries badge - a red non-2xx status or a 301 there tells you whether the problem is your receiver or the URL.
Because delivery times out after 5 seconds and is not retried indefinitely, make the n8n webhook node return 200 immediately and do the Slack post on the branch after it - and make the handler idempotent so a re-delivered event never double-posts.
Best practices
- Always set a secret and verify signatures. The HMAC-SHA256 signature is what proves a request really came from Thirdlane; without it, anyone who learns your URL could forge events.
- Subscribe only to events you use. Selecting specific events (or scoped wildcards like
contact.*) keeps traffic and noise down versus subscribing to everything. - Respond fast and process asynchronously. Delivery times out after 5 seconds and does not follow redirects, so your receiver should return
2xximmediately and do heavy work in the background. - Make your receiver idempotent. Design handlers so that if the same event is delivered more than once, it does not create duplicate records.
- Validate with a request inspector first. Point the URL at webhook.site (or similar), click Test Webhook, and confirm the payload and headers before wiring up real logic.
- Watch the delivery log. Check the Deliveries badge after going live; repeated non-2xx statuses point to a receiver problem to fix.
Related documentation
- System Webhooks - the cross-tenant equivalent for platform administrators who need provisioning events from every tenant in a single subscription.
- Automations - no-code workflows via Zapier.
- REST API - pull data or push changes programmatically.