Guide to Zapier Webhooks: Features and Best Practices
Zapier webhooks let a Zap send data to your own application. The Webhooks by Zapier action makes an HTTP request from any step of a Zap, so a new form response, CRM record or spreadsheet row can reach your API without a dedicated integration. Unlike most platforms in this series, Zapier doesn't sign these requests or define event types: you decide what is sent and how it is authenticated.
This guide covers sending webhooks from a Zap to an endpoint you control: the action's options, how to authenticate the request, and the best practices for receiving it in production. To go the other way, from an external service into Zapier, see how to receive and replay external webhooks in Zapier with Hookdeck.
What are Zapier webhooks?
Webhooks by Zapier is a built-in Zapier app. As an action, it sends one HTTP request each time the Zap runs, with a body built from the Zap's earlier steps. The request goes to the URL you enter, with the method, payload format, headers and authentication you choose.
Because you build the request yourself, there is no fixed payload, no event name and no signature. Anything your receiver relies on, from a type field to a secret, has to be added in the action.
Zapier webhook features
| Feature | Details |
|---|---|
| Action | Webhooks by Zapier |
| Methods | GET, POST, PUT, or Custom Request for PATCH, DELETE and anything that needs raw input |
| Payload types | Form (URL-encoded), JSON, XML, or Raw |
| Body | Key-value Data fields with __ nesting, or raw text with Custom Request |
| Headers | Headers section for custom headers |
| Authentication | Basic Auth field, or a secret you add as a header |
| Signature | None |
| Event types | None; add your own field if you need one |
| Payload limit | 5MB for actions |
| Rate limits | Apply to Webhooks by Zapier |
Common events
Zapier has no webhook events of its own. Each request carries whatever the Zap's Data section produces. With a templated action such as POST, these Data fields:
order | 1234
item__price | 19.99
item__sku | SKU-1
become this JSON body. The | only separates the left and right fields in Zapier's editor, and in a real Zap the values would be mapped from earlier steps:
{
"order": "1234",
"item": { "price": "19.99", "sku": "SKU-1" }
}
If you leave the Data section blank, Zapier sends every field from the previous step. That is handy for a quick test but means the body changes whenever the trigger app changes its output, so map fields explicitly for production.
When several Zaps post to the same endpoint, add a field such as event or zap to each one so your receiver can route them.
Setting up Zapier webhooks
- Add a Webhooks by Zapier action to your Zap and pick
POST(or Custom Request if you needPATCH,DELETE, nested arrays or empty values). - Choose a Payload Type. JSON is the easiest to parse on the receiving side.
- Enter your endpoint URL. Zapier recommends putting parameters in the Data fields rather than the URL.
- Fill in the Data fields, mapping values from earlier steps.
- Under Headers, add a secret header, for example
AuthorizationwithBearer <your-secret>. Alternatively, use the Basic Auth field. - Test the step and check that your endpoint received the request.
Securing Zapier webhooks
Zapier doesn't sign the request, so your endpoint has to check the credential you added in the action. Generate a long random secret, store it in the Zap's header and in your server's environment, and compare the two in constant time.
const crypto = require('crypto');
const express = require('express');
function verifyZapierSecret(headers, expected_value) {
const received_value = headers['authorization'];
if (typeof received_value !== 'string' || typeof expected_value !== 'string') return false;
const received = Buffer.from(received_value, 'utf8');
const expected = Buffer.from(expected_value, 'utf8');
return received.length === expected.length && crypto.timingSafeEqual(received, expected);
}
const app = express();
app.post('/webhooks/zapier', express.raw({ type: '*/*' }), (req, res) => {
const secret = process.env.ZAPIER_WEBHOOK_SECRET;
if (!secret) return res.sendStatus(500); // fail closed
if (!verifyZapierSecret(req.headers, `Bearer ${secret}`)) {
return res.sendStatus(401);
}
// The body format depends on the action's Payload Type.
const body = req.body.toString('utf8');
// Parse as JSON, form data or XML to match the Zap, queue it, then respond.
res.sendStatus(200);
});
The same check in Python:
import hmac
import os
def verify_zapier_secret(headers, expected_value: str) -> bool:
received_value = headers.get("authorization")
if not received_value or not expected_value:
return False
return hmac.compare_digest(received_value.encode("utf-8"), expected_value.encode("utf-8"))
# In FastAPI:
# verify_zapier_secret(request.headers, f"Bearer {os.environ['ZAPIER_WEBHOOK_SECRET']}")
If you use the Basic Auth field instead, check the Authorization: Basic ... header against the credentials you configured, in the same constant-time way.
Make Zapier webhooks production-ready. Hookdeck Event Gateway checks the secret header from your Zap, queues every request, and lets you replay any run your service failed to process.
Hookdeck's Zapier source type checks a header that you name, such as Authorization, against the exact value you enter, including any prefix such as Bearer . The header name is matched case-insensitively and the value must match exactly. For Basic Auth, enter Authorization as the header and Basic followed by the base64-encoded credentials as the value.
Zapier webhook limitations and pain points
No signature
The Problem: Anyone who learns your endpoint URL can send requests that look like they came from your Zap.
Why It Happens: Webhooks by Zapier sends a plain HTTP request. Zapier has no signing secret for this action, and its docs point to a private app on the Developer Platform for more advanced authentication.
Workarounds:
- Add a long random secret in a header and check it on every request.
- Use HTTPS so the header can't be read in transit, and rotate the secret if a Zap is shared or exported.
How Hookdeck Can Help: Hookdeck verifies the secret header and stops requests that fail before they reach your service, so your service only sees requests from your Zaps.
The body is only as stable as your Zap
The Problem: A field your handler expects disappears or changes type.
Why It Happens: The body is built from earlier steps. A blank Data section forwards every field from the previous step, so a change in the trigger app changes the body. Custom Request sends exactly what you typed, without validation.
Workarounds:
- Map each field explicitly in the Data section.
- Validate the body against a schema in your handler and reject what doesn't match.
- Run Custom Request bodies through a JSON validator before turning the Zap on, as Zapier recommends.
How Hookdeck Can Help: Hookdeck keeps every request's headers and body, so you can see exactly what a Zap sent and replay it after you fix the mapping.
Payload size and rate limits
The Problem: Large records or bursts of Zap runs fail.
Why It Happens: Webhooks by Zapier actions have a 5MB payload limit, and rate limits apply to the app.
Workarounds:
- Send IDs instead of whole records and fetch the details from your side.
- Keep your endpoint fast so a burst of Zap runs doesn't back up.
How Hookdeck Can Help: Hookdeck accepts the request immediately and delivers it to your service at a rate you set, so bursts from busy Zaps don't overload your API.
Best practices
Pick one payload type and parse for it
Zapier sends Form, JSON, XML or Raw depending on the action's setting. Read the raw body and parse it for the format you chose rather than relying on a framework parser that may not match.
Add your own event field
Give each Zap a fixed field such as event so one endpoint can serve several Zaps and log which one sent a request.
Make handlers idempotent
If you rerun a Zap or replay a request, the same data arrives again. Include a stable ID from the trigger app in the body and deduplicate on it. See our guide to webhook idempotency.
Acknowledge fast and process asynchronously
Return a 2xx once the request is stored and do the work in the background. See why to process webhooks asynchronously.
Conclusion
Webhooks by Zapier sends whatever your Zap builds, in the format and with the headers you choose. Because Zapier doesn't sign the request, add a secret header or Basic Auth and check it on every request, map the Data fields explicitly, and include your own event field and ID so the receiver can route and deduplicate.
Hookdeck Event Gateway checks your Zap's secret, queues every request, and holds it until your service has processed it.
Get started with Hookdeck for free and handle Zapier webhooks reliably in minutes.