# Webhook signature schemes compared

Every scheme here signs with HMAC-SHA256. They differ in what is signed, how the signature is encoded, how the secret becomes the HMAC key, whether a timestamp limits replays, and how the sender retries failed deliveries.

## How each request is signed

| Scheme | Headers | Signed message | Encoding | Key | Timestamp tolerance |
| --- | --- | --- | --- | --- | --- |
| Standard Webhooks | `Webhook-Id`, `Webhook-Timestamp`, `Webhook-Signature` | `HMAC-SHA256(key, id + "." + timestamp + "." + body)` | Base64 | Signing secret, with the whsec_ prefix removed and the rest Base64-decoded | Not fixed by the spec. The official libraries allow 5 minutes. |
| Stripe | `Stripe-Signature` | `HMAC-SHA256(secret, t + "." + body)` | Hex | Endpoint signing secret, used as text | 5 minutes, using t= timestamp |
| GitHub | `X-Hub-Signature-256` | `HMAC-SHA256(secret, body)` | Hex | Webhook secret, used as text | None. No timestamp is signed, so a signature never expires. |
| Shopify | `X-Shopify-Hmac-Sha256` | `Base64(HMAC-SHA256(client secret, body))` | Base64 | App client secret, used as text | None. No timestamp is signed, so a signature never expires. |
| Slack | `X-Slack-Request-Timestamp`, `X-Slack-Signature` | `HMAC-SHA256(secret, "v0:" + timestamp + ":" + body)` | Hex | Signing secret, used as text | 5 minutes, using X-Slack-Request-Timestamp |
| Cascadehook | `Webhook-Id`, `Webhook-Timestamp`, `Webhook-Signature` | `HMAC-SHA256(key, id + "." + timestamp + "." + body)` | Base64 | Signing secret, with the whsec_ prefix removed and the rest Base64-decoded | 5 minutes in the reference receivers. |

## Retries and response deadlines

| Sender | Automatic retries | Response deadline | Source |
| --- | --- | --- | --- |
| Standard Webhooks | Recommends exponential backoff with jitter over several days. Each sender sets its own schedule. | Recommends a 15 to 30 second timeout. | [Standard Webhooks specification](https://github.com/standard-webhooks/standard-webhooks/blob/main/spec/standard-webhooks.md) |
| Stripe | Up to three days with exponential backoff in live mode; three times over a few hours in a sandbox. | Not stated. Stripe asks for a quick 2xx before any slow work. | [Stripe: Receive events in your webhook endpoint](https://docs.stripe.com/webhooks) |
| GitHub | None. Failed deliveries must be redelivered by hand or through the REST API. | 10 seconds. | [GitHub: Handling failed webhook deliveries](https://docs.github.com/en/webhooks/using-webhooks/handling-failed-webhook-deliveries) |
| Shopify | Up to eight times over four hours. The subscription is removed if failures persist. | 5 seconds. | [Shopify: Troubleshooting webhooks](https://shopify.dev/docs/apps/build/webhooks/troubleshooting-webhooks) |
| Slack | Up to three retries: almost immediately, after 1 minute, and after 5 minutes. | 3 seconds. | [Slack: Events API](https://docs.slack.dev/apis/events-api/) |
| Cascadehook | Up to 8 attempts within 72 hours, with jittered backoff from about 15 seconds to 18 hours. 408, 429, 5xx, timeouts, and network errors are retried; Retry-After can lengthen a wait. | 30 seconds per attempt. | [Cascadehook: Deliveries, retries, and replay](https://cascadehook.com/docs/concepts/deliveries) |

## What the differences mean

- GitHub and Shopify sign only the body, so a captured request keeps a valid signature indefinitely. Deduplicate on the provider's delivery or event ID to resist replays.
- Stripe, Slack, and Standard Webhooks sign a timestamp with the body, so receivers can reject old requests. Keep the server clock synced with NTP.
- Standard Webhooks also signs the message ID, which doubles as an idempotency key for the receiver.
- Standard Webhooks decodes its whsec_ secret from Base64, while Stripe uses its whsec_ secret as text. Treating one like the other is a common cause of mismatches.
- Response deadlines range from 3 to 30 seconds. Acknowledge quickly and move slow work to a queue.

## Verifiers

- [Standard Webhooks verifier](https://cascadehook.com/tools/webhook-signature-verifier.md)
- [Stripe verifier](https://cascadehook.com/tools/stripe-webhook-signature-verifier.md)
- [GitHub verifier](https://cascadehook.com/tools/github-webhook-signature-verifier.md)
- [Shopify verifier](https://cascadehook.com/tools/shopify-webhook-hmac-verifier.md)
- [Slack verifier](https://cascadehook.com/tools/slack-request-signature-verifier.md)

Policies were checked against each provider's documentation on November 7, 2026.
