Providers
What ships today, what works via Standard Webhooks, and the nine scheme families behind it all.
Shipping today: Stripe, GitHub, Discord, Twilio, Google Pub/Sub (which also carries Gmail push, Play RTDN, and Workspace Events), and Standard Webhooks — the last of which covers every Svix-backed vendor, with named wrappers for Resend, Clerk, Polar, and Replicate.
Stripe
HMAC over timestamp + body, Stripe-Signature.
GitHub
HMAC over the raw body, X-Hub-Signature-256.
Discord
Ed25519 signatures; interactions and Webhook Events.
Twilio
Signs your public URL + sorted params, not the body.
Google Pub/Sub
OIDC JWT + JWKS; unwraps the push envelope for you.
Standard Webhooks
Resend, Clerk, Polar, Replicate, OpenAI, Svix — one spec.
Any Standard Webhooks vendor without a named wrapper works right now:
import { standardWebhooks } from 'webhooks-sdk/standard-webhooks'
standardWebhooks({ id: 'openai', secret: process.env.OPENAI_WEBHOOK_SECRET! })
That covers OpenAI, Dodo Payments, Stytch, Loops, and Svix itself.
Scheme families
Every webhook provider claims a bespoke signature scheme. Most of them are not bespoke at all — roughly nine families cover almost everything, and implementing a family is the expensive part. Each additional provider inside a family is then a header name, an encoding, and a test fixture.
| # | Family | How it works | Replay-safe on its own | Examples |
|---|---|---|---|---|
| 1 | HMAC over raw body | HMAC(secret, rawBody), hex or base64, in one header |
❌ — pair with an idempotency store | GitHub, Shopify, Lemon Squeezy, Sentry |
| 2 | HMAC over timestamp + body | HMAC(secret, "{ts}.{body}"), timestamp sent alongside |
✅ | Stripe, Paddle, Slack, WorkOS |
| 3 | Standard Webhooks / Svix | HMAC(base64(secret), "{id}.{ts}.{body}"), versioned v1,… list |
✅ | Resend, Clerk, Polar, OpenAI |
| 4 | Ed25519 | Public-key signature over ts + body; no shared secret to leak |
✅ | Discord |
| 5 | JWT / JWKS | Signed token in a header, verified against a rotating public key set | ✅ (via exp) |
Google Pub/Sub, Plaid, Wix |
| 6 | X.509 cert chain | RSA signature; fetch and validate the signing cert from the provider | ✅ | PayPal, AWS SNS |
| 7 | Canonical string HMAC | Signs a reconstructed string (URL + sorted params), not the raw body | ⚠️ varies | Twilio, Square, Adyen, Trello |
| 8 | Shared token compare | A static secret echoed in a header; constant-time compare only | ❌ | GitLab, Telegram, Google Drive |
| 9 | None / out-of-band | No signature — re-fetch the resource by id, or use mTLS/basic auth/IP allowlist | ❌ | Mollie, Postmark, Docker Hub |
Families 1–4 are pure Web Crypto and ship in the zero-dependency core. Families 5 and 6 need a fetch of remote key material, so they carry a pluggable cache. Family 7 is the awkward one: the signature covers a string the SDK has to rebuild, which means the provider must know the public URL of your endpoint — proxies and rewrites break it, so it’s configurable.