Zendesk Webhooks: Setup, Signatures and Payload Examples

Create Zendesk webhooks the right way: triggers vs event subscriptions, the payload format, verifying X-Zendesk-Webhook-Signature, retries, and a fast local dev loop.

Zendesk webhooks guide

Zendesk's webhooks moved on from the old "HTTP targets" years ago — today there is one Webhooks system in Admin Center that can be wired to business rules or subscribe directly to typed events, with proper HMAC signatures on every delivery. This guide covers choosing between those two invocation styles, what the payloads look like, verifying the signature, and testing against real deliveries.

Create the webhook

Admin Center → Apps and integrations → Webhooks → Create webhook. The first decision is how it gets invoked:

  • Trigger or automation — the webhook fires when a business rule matches (ticket created, priority changed to urgent, SLA about to breach…). The request body is whatever the rule author builds, usually JSON with placeholders. Great when a human designs the notification.
  • Zendesk events — the webhook subscribes to typed event streams like zen:event-type:ticket.status_changed, ticket.priority_changed, or user/organization events. The body is a fixed envelope Zendesk defines. This is what you want for programmatic consumers.

Then set the endpoint URL (public HTTPS), request method, and optional authentication (basic auth, bearer token, or API key header) — this auth is outbound config Zendesk attaches to requests, separate from the signature below.

The payload

Event-subscription deliveries share a stable envelope:

{
  "account_id": 10000001,
  "id": "01JEXAMPLEEVENT0000000000",
  "subject": "zen:ticket:15492",
  "time": "2026-01-15T10:30:00Z",
  "type": "zen:event-type:ticket.status_changed",
  "zendesk_event_version": "2022-11-06",
  "detail": {
    "id": "15492",
    "status": "open",
    "priority": "normal",
    "subject": "Cannot reset my password",
    "assignee_id": "400000000001"
  },
  "event": { "previous": "new", "current": "open" }
}

type names the event, detail carries the entity snapshot, and event describes the change itself (previous → current). Trigger-based webhooks look however the rule author shaped them — which is exactly why you should capture a real one before writing parsing code: point the webhook at a free Webhook Bin for a minute (the bin's sample catalog also has a ready-made ticket.status_changed event with the full header set).

Verify the signature

Every delivery — regardless of invocation style — carries:

X-Zendesk-Webhook-Signature: <base64 HMAC-SHA256>
X-Zendesk-Webhook-Signature-Timestamp: 2026-01-15T10:30:00Z

The signed string is the timestamp concatenated directly with the raw body (no separator):

const expected = crypto.createHmac('sha256', secret)
  .update(timestamp + rawBody)
  .digest('base64');

The signing secret lives on the webhook's detail page (Reveal secret) or via GET /api/v2/webhooks/{id}/signing_secret. Two details that cause most failures: hashing a re-serialized body instead of the raw bytes, and forgetting the timestamp prefix. Check your implementation interactively with our free Zendesk webhook signature verifier — and reject deliveries whose timestamp is stale to block replays.

Delivery, retries and the activity log

Zendesk expects a fast 2xx. Failed deliveries are retried a limited number of times with backoff, and webhooks that keep failing get automatically deactivated — a surprise you discover days later when tickets stop syncing. Defenses:

  1. Acknowledge immediately, process asynchronously.
  2. Watch the activity log on the webhook's admin page — it records each attempt, response code and latency.
  3. If your consumer is flaky or occasionally deployed, front it with a stable relay endpoint that stores every event and keeps retrying towards your side — Zendesk always sees a healthy 200 and never deactivates the webhook.

Local development

Zendesk needs a public URL, your handler runs on localhost — the standard bridge applies: inspect in a Webhook Bin, then relay forward --bucket zendesk http://localhost:8080/webhook. Full walkthrough: Test Zendesk webhooks locally.