Providers
Find your provider — Stripe, GitHub, Discord, Twilio, Google Pub/Sub, and every Svix-backed vendor.
Shipping today: Stripe, GitHub, Discord, Twilio, Google Pub/Sub (which also carries Gmail push, Play RTDN, and Workspace Events), OpenAI, Resend, Loops, Clerk, Polar, Dodo Payments, Replicate, and Standard Webhooks — the last of which covers every other Svix-backed vendor.
Stripe
Payment events, replay-safe, zero-downtime secret rotation.
GitHub
Repository, organization, and GitHub App webhooks.
Discord
Interactions and Webhook Events — both PINGs answered right.
Twilio
SMS, voice, and status callbacks — URL signing handled.
Google Pub/Sub
Also carries Gmail push, Play RTDN, and Workspace Events.
OpenAI
Response, batch, fine-tuning, eval, and call events.
Resend
Email delivery, engagement, contact, and domain events.
Loops
Contact, mailing list, email send, and engagement events.
Clerk
User, session, organization, and billing events.
Polar
Checkout, order, subscription, and benefit events.
Dodo Payments
Payment, subscription, refund, dispute, and payout events.
Replicate
Prediction status updates, from starting to succeeded.
Standard Webhooks
Stytch, Svix itself, and any other Svix-backed vendor — one spec.
Any Standard Webhooks vendor without a named wrapper works right now:
import { standardWebhooks } from 'webhooks-sdk/standard-webhooks'
standardWebhooks({ id: 'svix', secret: process.env.SVIX_WEBHOOK_SECRET! })
That covers Stytch and Svix itself.
Scheme families
Every webhook provider claims a bespoke signature scheme. Most of them are not bespoke at all — roughly nine patterns cover almost everything. Two things in this table are worth knowing about your provider: how it verifies, and whether it’s replay-safe on its own or needs an idempotency store alongside.
| # | 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, Loops, 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 5 and 6 verify against remote key material, so those providers
carry a pluggable key cache. Family 7 is the awkward one for you as the
receiver: the provider signs the public URL of your endpoint, so a proxy or
rewrite in front of your app breaks verification — which is why the
Twilio provider takes an explicit url.