Zapier Webhook: Example Payload, Headers and Signature

Zapier works in both directions. A Webhooks by Zapier action posts to your URL; a Catch Hook trigger gives you a URL to post to. Here is what each request looks like.

No webhook URL yet. Creating one needs no account.

Request details
Requests sent to your webhook URL appear here: method, headers and the body exactly as it arrived.

The button posts the example below to your webhook URL from your browser. It is not sent by Zapier, it carries your browser's User-Agent, and its signature is a placeholder that will not verify. To see a real delivery, follow the steps further down.

Last updated . How this page is checked.

How the webhook URL works. It is a public address that records whatever is sent to it and answers 200. An inbox keeps the 50 most recent requests, accepts bodies up to 256 KB, and is deleted 24 hours after it was created — or sooner if you press Delete URL or our server restarts, because requests are held in memory and never written to disk.

Anyone who has the URL can read what it received. Use sandbox and test-mode accounts, do not route production traffic or customer data through it, and delete it when you are done. Privacy details.

What is a Zapier webhook?

Zapier is not a provider with its own event stream — it is plumbing. Its built-in Webhooks by Zapier app exposes two halves. As a trigger (Catch Hook), Zapier hands you a URL under hooks.zapier.com, and any request you send there starts the Zap. As an action (POST, PUT, GET or Custom Request), a Zap sends a request to a URL of yours with whatever fields you mapped.

That means the payload is not fixed. An outbound request contains exactly the keys you typed into the Data fields, and an inbound Catch Hook accepts nearly any JSON, form or query-string body and flattens it into fields for later steps. The sample below is the outbound side — a Zap posting to you — because that is the one worth inspecting on a URL you control.

What a Zapier webhook request looks like

The request line and headers as they reach your server, followed by the body. Ids, tokens and the signature are placeholders.

POST /your/webhook/path HTTP/1.1
Host: your-server.example
Content-Type: application/json
Accept: application/json
User-Agent: Zapier
X-Webhook-Secret: put-a-long-random-value-here
{
  "event": "form.submitted",
  "submitted_at": "2026-01-01T12:00:00Z",
  "name": "Jon Doe",
  "email": "jon@example.com",
  "plan": "starter",
  "source": "Contact form"
}

Every key here was chosen by whoever built the Zap; there is no schema. With the default form payload type the same data arrives as event=form.submitted&name=Jon+Doe…, and unless the action's Unflatten option is on, a key written as customer__email stays flat rather than becoming a nested object.

Headers Zapier sends

HeaderExampleWhat it is
Content-Typeapplication/jsonFollows the action's Payload Type: json, form (urlencoded, the default), xml or raw.
Acceptapplication/jsonSent by default.
User-AgentZapierIdentifies the sender. Anyone can set the same value.
X-Webhook-Secretput-a-long-random-value-hereNot sent by default — a header you add in the action's Headers field so your endpoint can recognise the Zap.

Header names are case-insensitive. Your framework may show them lower-cased, and HTTP/2 always does.

Zapier does not sign requests

There is no signature header and no shared secret. A request from a Webhooks by Zapier action is authenticated only by whatever you add to it: a custom header, Basic auth credentials in the action's Basic Auth field, or a token in the URL. Zapier sends from shared cloud address ranges, so an IP allow-list identifies "Zapier", not "my Zap".

The practical pattern is a long random value in a custom header, checked in constant time, over HTTPS. For inbound Catch Hook URLs the URL itself is the credential — anyone who has it can trigger the Zap — so treat it like a password and never commit it to a repository.

const crypto = require('crypto');

// A shared secret you put in the Zap action's Headers field
function fromMyZap(req, secret) {
  const a = Buffer.from(req.headers['x-webhook-secret'] || '');
  const b = Buffer.from(secret);
  return a.length === b.length && crypto.timingSafeEqual(a, b);
}

Responses, failures and the Catch Hook reply

For an outbound action, Zapier treats a 2xx as success and makes the response body available to later steps; a 4xx or 5xx marks the step as errored in the Zap's history. Whether an errored run is replayed depends on the account's replay settings rather than on anything your endpoint can control, so do not design around automatic retries.

For an inbound Catch Hook, Zapier answers almost immediately with a small JSON receipt — a status of success plus identifiers for the attempt and request — before the Zap has run. That 200 means "received", not "your Zap worked". The Zap's own history is where failures show up.

See exactly what your Zap sends

  1. Press Create webhook URL at the top of this page and copy the address.
  2. In your Zap, add an action step, choose Webhooks by Zapier and the POST event.
  3. Paste the address into URL, set Payload Type to json, and map the Data fields.
  4. Add any headers you plan to use in production, then run the step's test.
  5. The request appears in the inbox above — the real method, headers and body your endpoint will have to handle.

This is the quickest way to answer "is Zapier sending JSON or form data?" and "did my nested key unflatten?" without deploying anything.

To run a caught request against your own code, select it and press Open in API Tester: the method, headers and body are loaded into the request console, where you enter your server's public URL and send it. A body you edit will no longer match its signature — that is the signature doing its job.

Things that catch people out

  • The default payload type is form, not JSON. A handler that only parses JSON sees an empty body until the action is switched.
  • Catch Hook flattens and picks. Nested JSON becomes double-underscore field names, and if you post an array the Zap runs once per element. Use Catch Raw Hook when you need the untouched body and headers — for instance to verify another provider's signature inside a Code step.
  • Empty values vanish. A mapped field with no value is omitted from the outbound body rather than sent as null, so do not treat "key missing" as an error.

api-tester.com is independent and is not affiliated with Zapier. Providers change header names, limits and retry schedules; treat the official Zapier documentation as the source of truth.

Related examples and tools

Other webhooks with no signature

References

These links leave api-tester.com, which is independent of the companies and projects they point to.

Zapier webhook FAQ

What does a Zapier webhook request look like?

An ordinary HTTP request with a User-Agent of Zapier and a body containing exactly the fields mapped in the action — JSON, form-encoded, XML or raw depending on the Payload Type setting.

Does Zapier sign its webhook requests?

No. There is no signature header. Authenticate the request yourself with a custom secret header, Basic auth or a token, and always use HTTPS.

What is the difference between Catch Hook and Catch Raw Hook?

Catch Hook parses the incoming body into fields for later steps. Catch Raw Hook passes the unparsed body and the request headers through, which you need for signature verification or unusual formats.

What does a Zapier Catch Hook URL return?

A 200 response with a short JSON receipt containing a success status and identifiers for the attempt and request. It is returned before the Zap runs, so it confirms receipt only.

Why is my endpoint receiving form data from Zapier instead of JSON?

Because the action's Payload Type defaults to form. Change it to json in the step's settings.