# Generate Webhook Signatures

Generate Stripe, GitHub, Slack, Shopify, Standard Webhooks, Svix, Square, Twilio, Paddle, or custom HMAC webhook headers from a raw payload and secret.

## Run it

- **CLI:** `gizza tool webhook-signature-generator '{"id":"evt_test","type":"payment_intent.succeeded"}' 'secret=whsec_test_secret'`
- **Web:** https://gizza.ai/tools/webhook-signature-generator/
- **Agents:** machine-readable descriptor (parameters JSON Schema) at https://gizza.ai/tools/webhook-signature-generator/tool.json

## Inputs

- `payload` — Raw payload _(field)_
- `secret` — Signing secret _(field)_
- `provider` — Provider _(field)_
- `timestamp` — Timestamp _(field)_
- `message_id` — Message id _(field)_
- `url` — Endpoint URL _(field)_
- `algorithm` — Custom algorithm _(field)_
- `encoding` — Custom signature encoding _(field)_
- `secret_encoding` — Secret encoding _(field)_
- `template` — Custom signed-string template _(field)_
- `header_name` — Custom header name _(field)_
- `signature_prefix` — Custom signature prefix _(field)_
- `output` — Output _(field)_

## Output

- Signature result (text)

## Query parameters

Open the tool pre-filled and auto-run via URL:

- `payload` — Raw payload
- `secret` — Signing secret
- `provider` — Provider
- `timestamp` — Timestamp
- `message_id` — Message id
- `url` — Endpoint URL
- `algorithm` — Custom algorithm
- `encoding` — Custom signature encoding
- `secret_encoding` — Secret encoding
- `template` — Custom signed-string template
- `header_name` — Custom header name
- `signature_prefix` — Custom signature prefix
- `output` — Output

Example: `https://gizza.ai/tools/webhook-signature-generator/?payload=%7B%22id%22%3A%22evt_test%22%2C%22type%22%3A%22payment_intent.succeeded%22%7D&secret=whsec_test_secret&provider=stripe&timestamp=1700000000&message_id=msg_2KWPBgLlAfxdpx2AI54pPJ85f4W&url=https%3A%2F%2Fexample.com%2Fwebhook&algorithm=sha256&encoding=hex&secret_encoding=auto&template=%7Btimestamp%7D.%7Bpayload%7D&header_name=X-Signature&signature_prefix=sha256%3D&output=all`

---

## About this tool

Webhook Signature Generator builds the HMAC headers that webhook providers send with a delivery. Paste the exact raw body, the endpoint's signing secret, and a fixed timestamp when the provider uses one; the tool returns the signed byte string, the encoded HMAC, finished header lines, and an optional replay `curl` command.

A worked Stripe example:

1. Payload: `{"id":"evt_test","type":"payment_intent.succeeded"}`
2. Secret: `whsec_test_secret`
3. Provider: `stripe`
4. Timestamp: `1700000000`
5. Output: `headers`

The primary result is a `Stripe-Signature` header in the `t=1700000000,v1=<hex hmac>` format. Switch the provider to GitHub, Slack, Shopify, Standard Webhooks, Svix, Square, Twilio, or Paddle to use that provider's canonical string-to-sign and header layout.

Use `custom` when a webhook source only says "HMAC this string". The custom mode supports `{payload}`, `{timestamp}`, `{id}`, and `{url}` placeholders, selectable HMAC algorithms, hex/base64 encodings, and your own header name/prefix.

Limits and edge cases:

- The payload cap is 2 MiB so browser and Service Worker runs stay responsive.
- The payload is signed exactly as pasted. JSON whitespace, key order, newline style, and form encoding are part of the signature.
- Timestamped providers accept Unix seconds or ISO-8601 input. Millisecond timestamps are rejected with a hint.
- Standard Webhooks and Svix `whsec_` secrets are base64-decoded in `auto` mode; Stripe `whsec_` secrets are literal text.
- This tool generates signatures for testing your own endpoint. It does not verify an incoming request and it does not send traffic unless you copy and run the cURL command yourself.
- Asymmetric providers such as SendGrid ECDSA, PayPal certificates, and Discord Ed25519 are outside this HMAC-only model.

## FAQ

<details>
<summary>Why does changing JSON formatting change the signature?</summary>

Webhook providers sign the raw request body bytes, not the parsed JSON object. A pretty-printed JSON document, compact JSON document, or reordered object can all represent the same data while producing different bytes and therefore different HMACs. Paste the body exactly as your receiver sees it.

</details>

<details>
<summary>What timestamp should I use?</summary>

Use the timestamp from a real delivery when you want to reproduce or debug a mismatch. Leave it blank when generating a fresh replay header for providers such as Stripe or Slack; the page and CLI fill the current Unix seconds. Receivers usually reject old timestamps, so a historical signature may need a test-mode bypass on your endpoint.

</details>

<details>
<summary>Why are Standard Webhooks and Svix secrets decoded but Stripe secrets are not?</summary>

Standard Webhooks and Svix define `whsec_` as a prefix before base64 key material, so `auto` strips the prefix and decodes the rest. Stripe's `whsec_...` value is used as literal text for the HMAC key. Mixing those conventions is a common source of signatures that look valid but never verify.

</details>

<details>
<summary>Can this verify incoming webhook requests?</summary>

No. It is a generator for replay and endpoint tests. To verify a request, compute the same signature with the raw body and compare it to the incoming header using constant-time comparison in your server code, along with provider-specific timestamp and replay checks.

</details>

## Related tools

- [HMAC Generator](https://gizza.ai/tools/hmac-generate/): Generate an HMAC of any message and secret key in your browser — HMAC-SHA256, SHA-1, SHA-512, SHA-3 or MD5, hex or base64 output. Free and private.
- [Critical Path Method Calculator](https://gizza.ai/tools/critical-path-calculator/): Find the critical path, project duration, earliest/latest start & finish, and slack from a task list — with PERT three-point estimates. Runs in your browser.
- [Email Reply Cleaner](https://gizza.ai/tools/email-reply-cleaner/): Paste a replied or forwarded email and get just the fresh message — quoted lines, the reply chain, and signatures removed. Toggle each pass. Runs in your browser.
- [Flask Session Cookie Signer](https://gizza.ai/tools/flask-session-sign/): Sign Flask session cookies from a JSON payload and SECRET_KEY, with Flask defaults plus timestamp, digest, salt, and compression controls.
- [HKDF key derivation](https://gizza.ai/tools/hkdf-derive/): Derive keys with HKDF, the HMAC-based extract-and-expand KDF from RFC 5869 — choose hash, salt, info label, length and hex/base64 output, all in your browser.
