Authentication
Anyone who knows a webhook URL can send it a request, so authentication is what stops a stranger firing your Shopify Flow workflows. Set it per webhook, under the webhook's Security section.
The three methods
| Method | How the caller proves itself | Use it when |
|---|---|---|
| None | Nothing | Testing only - never in production |
| Static token | A fixed secret in a request header | Almost every integration (n8n, Make, Zapier, your own code) |
| HMAC SHA-256 | A signature computed from the request and a shared secret | The sender signs its webhooks (Stripe, GitHub, Slack, …) |
[!WARNING] None means the URL is the only secret, and URLs leak - into logs, browser history, screenshots and support tickets. Use it to get a first request flowing, then switch.
Static token
Press the generate button on the webhook to get a strong random token, or paste your own. The caller sends it in a header:
curl -X POST https://your-app-url/webhook/ab12cd34 \
-H "Content-Type: application/json" \
-H "X-Api-Key: your-token" \
-d '{"orderId":"1001"}'
Changing the header name
Some systems can only send a header they already use. Set Auth header name in Advanced
Settings and we read the token from that header instead of X-Api-Key:
-H "X-Custom-Auth: your-token"
Header names are case-insensitive. Reserved names are rejected - Host, Authorization,
Cookie, X-Forwarded-*, X-Webhook-*, CF-* and similar. Those are set or rewritten by
proxies and CDNs, so a token read from one would be attacker-controllable.
HMAC SHA-256
The sender computes a signature over the request using a shared secret; we recompute it and compare. A leaked request cannot be replayed with altered content, because the body no longer matches the signature.
Provider presets
If your sender is one of these, pick the preset and we verify using that provider's exact scheme - header name, encoding and signing base string:
| Preset | Signature header |
|---|---|
| Stripe | Stripe-Signature |
| GitHub | X-Hub-Signature-256 |
| Shopify | X-Shopify-Hmac-Sha256 |
| Slack | X-Slack-Signature |
| Typeform | Typeform-Signature |
| Calendly | Calendly-Webhook-Signature |
Paste the signing secret from the provider's dashboard and you are done.
Generic HMAC
With no preset, we use our own scheme: the caller sends X-Signature, the HMAC-SHA256 of
the X-Webhook-* header values using the signing secret.
curl -X POST https://your-app-url/webhook/ab12cd34 \
-H "Content-Type: application/json" \
-H "X-Webhook-Data: value1value2" \
-H "X-Signature: <hmac-sha256 of the X-Webhook-* values>" \
-d '{"data":"payload"}'
What a rejection looks like
Failed authentication returns 401 with a JSON body naming the reason - see
History and troubleshooting for the full code list. Rejected calls still appear
in the Live Request Inspector while you are editing the webhook, so you can see exactly why
one bounced.
Keeping the secret safe
- The token is never returned by our REST API or MCP server at any access level - they report only whether one is set. See Developer API and MCP.
- It is encrypted at rest.
- Rotating it takes effect immediately, so update your sender first.
- Stored invocation history masks the auth header, so a screenshot of History does not leak your token.

