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.