Skip to content

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:

HeaderDescription
Content-Typeapplication/json
X-Webhook-EventThe event name (e.g., contact.created)
X-Webhook-TimestampUnix timestamp of the delivery
X-Webhook-SignatureHMAC-SHA256 signature (if a secret is configured)

Verifying Signatures

If a secret is configured, the system signs each payload using HMAC-SHA256. To verify:

  1. Concatenate the timestamp and the raw request body with a . separator
  2. Compute HMAC-SHA256 using the shared secret
  3. Compare the result with the X-Webhook-Signature header

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 requires https://
  • 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.

  1. Get a receiving URL. In n8n, add a Webhook node set to POST and copy its production URL (for a quick dry run you can use a webhook.site URL instead).
  2. 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.
  3. 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.
  4. Test before going live. Click Test Webhook. n8n’s node shows an incoming request with headers X-Webhook-Event: webhook.test and X-Webhook-Signature. Confirm the body shape matches the payload format above.
  5. 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 to X-Webhook-Signature (same logic as the Python snippet above). Reject anything that does not match, then continue to the Slack node.
  6. Go live. Create a contact in the CRM. Within a second the webhook fires contact.created with the new contact in data; 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 2xx immediately 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.
  • 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.