Zendesk webhooks: triggers, event subscriptions and signature checks
To test a Zendesk webhook, set its endpoint URL to a free webhooks.sh bin (no signup, 48 hours, 100 requests a day) and use Test webhook or a trigger to see each request live. Zendesk signs every request with HMAC-SHA256, times out after 12 seconds and retries a few errors.
A Zendesk webhook sends an HTTP request to your endpoint when a subscribed Zendesk event or a trigger fires, signed with an x-zendesk-webhook-signature header. Pointing the endpoint at a free bin and clicking Test webhook shows the exact request headers and body right away. This page covers setup, events versus triggers, signature checks, authentication and the retry rules.
Send a Zendesk webhook to a free bin
- Create a free bin in your browser at view.webhooks.page or run
curl -X POST https://webhooks.sh/v1/binsto get youringest_urlandview_url. - In Zendesk Admin Center, go to
Apps and integrations>Webhooks>Webhooks>Create webhook, and pick eitherZendesk eventsorTrigger or Automation. - Give the webhook a name, paste the bin's ingest URL as the endpoint (such as
https://<bin>.webhooks.page/zendesk), and selectPOST,JSONand no authentication. - Click
Test webhook, choose an event, and clickSend test; the request shows up live in your bin while Zendesk's panel displays the bin's200response. - Create the webhook, or if you picked a trigger webhook, connect it to a trigger first and click
Finish setup.
You can also create the same webhook through the Zendesk API with POST /api/v2/webhooks.
# 1. Create a free bin (or open view.webhooks.page)
curl -X POST https://webhooks.sh/v1/bins
# 2. Or create a trigger webhook with the API
curl https://<subdomain>.zendesk.com/api/v2/webhooks \
-u <email>/token:<api_token> \
-H "Content-Type: application/json" \
-d '{"webhook": {
"name": "Bin test",
"endpoint": "https://<bin>.webhooks.page/zendesk",
"http_method": "POST",
"request_format": "json",
"status": "active",
"subscriptions": ["conditional_ticket_events"]}}'
Zendesk events or a trigger?
Zendesk locks in the connection method when you create the webhook, so you have to pick between Zendesk events and Trigger or Automation up front.
To wire up a trigger webhook, go to Admin Center > Objects and rules > Business rules > Triggers, add the Notify webhook action to a trigger, select your webhook, and write the payload using Zendesk placeholders. If you're using an automation instead, add the Notifications: Notify webhook action.
| Setting | Zendesk events | Trigger or automation |
|---|---|---|
| Fires on | Subscribed events: users, organizations, articles, messaging, tickets and more | Conditions you set in the trigger or automation |
| HTTP method | POST only | Your choice |
| Body | Fixed JSON event schema | JSON, XML or form-encoded, up to 16,000 characters |
| Change method later | No | No |
Verify x-zendesk-webhook-signature
Every delivery includes five headers: x-zendesk-account-id, x-zendesk-webhook-id, x-zendesk-webhook-invocation-id, x-zendesk-webhook-signature and x-zendesk-webhook-signature-timestamp. As detailed in Zendesk's webhook verification docs, the x-zendesk-webhook-signature value is the base64-encoded HMAC-SHA256 digest of the x-zendesk-webhook-signature-timestamp value concatenated directly with the raw request body, hashed using the webhook's signing secret. You can get that secret in Admin Center by clicking Reveal secret or through the API.
Zendesk only generates a real signing secret once you finish creating the webhook. If you use Test webhook during creation, Zendesk signs the test payload with a static secret (dGhpc19zZWNyZXRfaXNfZm9yX3Rlc3Rpbmdfb25seQ==) instead.
All five x-zendesk headers stay visible in a webhooks.sh bin, so you can copy a captured timestamp, raw body and signature straight into the HMAC signature verifier (set it to Custom HMAC, SHA-256 and base64, and put the timestamp right in front of {body} in the message template).
import { createHmac, timingSafeEqual } from "node:crypto";
export function isFromZendesk(headers, rawBody, signingSecret) {
const ts = headers["x-zendesk-webhook-signature-timestamp"] ?? "";
const sig = headers["x-zendesk-webhook-signature"] ?? "";
const expected = createHmac("sha256", signingSecret)
.update(ts + rawBody)
.digest("base64");
const a = Buffer.from(expected);
const b = Buffer.from(sig);
return a.length === b.length && timingSafeEqual(a, b);
}
Authentication and what the bin shows
Zendesk webhooks can be sent with no authentication, an API key in a header name you choose, basic authentication or a bearer token. If you test an authenticated webhook against a bin, keep in mind that the viewer redacts Authorization and any header whose name contains cookie, key, token or secret. You'll see that the header arrived, not the credential itself, while x-zendesk-webhook-signature and the other Zendesk headers remain readable.
If you add custom headers in Zendesk, these limits apply:
- You can add up to 5 custom headers per webhook.
- The webhook endpoint must use HTTPS.
- Header names can be up to 128 characters.
- Header values can be up to 1,000 characters.
- Names starting with
x-zendeskand several standard headers aren't allowed. - Don't put credentials in custom headers.
Retries, timeouts and the circuit breaker
Zendesk retries failed deliveries on a few specific status codes and uses a circuit breaker to pause endpoints that return too many errors.
Zendesk makes a best effort to deliver each event once, but the same action can still fire a webhook more than once, and events can be dropped while the circuit breaker is tripped. Make your handler idempotent and use x-zendesk-webhook-signature to catch duplicate deliveries. You can also query the last 7 days of delivery history via GET /api/v2/webhooks/{webhook_id}/invocations (pass filter[status]=failed to narrow it down) and /invocations/{invocation_id}/attempts.
Because a free bin answers every valid request with HTTP 200, testing against it won't trigger retries or trip the circuit breaker as long as you stay under 100 requests a day and 100KB bodies. See the webhook retries guide for more on how senders handle failures.
| Situation | What Zendesk does |
|---|---|
| Endpoint returns 409 | Retries up to 3 times |
| 429 or 503 with retry-after under 60 seconds | Retries |
| No response within 12 seconds | Times out, retries up to 5 times |
| 70% errors in 5 minutes, or over 1,000 errors | Circuit breaker blocks requests for 5 seconds |
| Fewer than 100 requests in 5 minutes | Circuit breaker never triggers |
| Many failures in a row | Webhook stays active |
Keep the URL or move to localhost
A free bin lasts 48 hours and accepts 100 requests a day, which is plenty for building triggers and checking payloads. If you want to keep using the same URL past 48 hours, claim the bin with a free Google sign-in before it expires to stop the timer and keep a rolling 30 days of request history.
When you need a permanent named URL on webhooks.host or higher volume, Solo ($12 a month, see pricing) gives you 250,000 requests a month, 5MB bodies and 90 days of history. It also includes the wsh CLI, so you can run wsh listen <endpoint> --to localhost:3000 to relay live Zendesk deliveries straight to your local server.
FAQ
How do I send a Zendesk webhook when a ticket is created?
Create a webhook connected to Trigger or Automation, then go to Objects and rules > Business rules > Triggers and build a trigger for new tickets. Add the Notify webhook action to that trigger, select your webhook, and write the JSON payload.
Can I change a Zendesk webhook from events to a trigger?
No. Zendesk fixes the connection method when you create the webhook, so you'll need to create a new one if you want to switch between Zendesk events and Trigger or Automation.
How do I verify a Zendesk webhook signature?
Concatenate the x-zendesk-webhook-signature-timestamp header value and the raw request body, compute the HMAC-SHA256 hash using the webhook's signing secret, and base64-encode the result. Compare that string to the x-zendesk-webhook-signature header.
Which secret signs Zendesk test requests?
Test requests sent while you're still creating a webhook are signed with Zendesk's static test secret, dGhpc19zZWNyZXRfaXNfZm9yX3Rlc3Rpbmdfb25seQ==, because Zendesk only generates a webhook's own signing secret after creation finishes.
Does Zendesk retry failed webhooks?
Yes. Zendesk retries 409 responses up to 3 times, 429 and 503 responses if they include a retry-after header under 60 seconds, and requests that time out after 12 seconds up to 5 times. Consecutive failures won't deactivate the webhook.
Why can't I see my API key in the test bin?
The viewer automatically redacts the values of headers whose names contain authorization, cookie, key, token or secret.
Last updated
Try it in 10 seconds.
Create a free bin at view.webhooks.page — no signup, no install. Point your sender at the URL and watch requests land live. Bins expire after 48 hours.