---
title: Providers
description: What ships today, what works via Standard Webhooks, and the nine scheme families behind it all.
sidebar:
  label: Overview
---

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**.

<CardGroup cols={2}>
  <Card title="Stripe" href="/docs/providers/stripe" icon="stripe">
    HMAC over timestamp + body, `Stripe-Signature`.
  </Card>
  <Card title="GitHub" href="/docs/providers/github" icon="github">
    HMAC over the raw body, `X-Hub-Signature-256`.
  </Card>
  <Card title="Discord" href="/docs/providers/discord" icon="discord">
    Ed25519 signatures; interactions and Webhook Events.
  </Card>
  <Card title="Twilio" href="/docs/providers/twilio" icon="twilio">
    Signs your public URL + sorted params, not the body.
  </Card>
  <Card title="Google Pub/Sub" href="/docs/providers/google-pubsub" icon="google-pubsub">
    OIDC JWT + JWKS; unwraps the push envelope for you.
  </Card>
  <Card title="Standard Webhooks" href="/docs/providers/standard-webhooks" icon="webhook">
    Resend, Clerk, Polar, Replicate, OpenAI, Svix — one spec.
  </Card>
</CardGroup>

Any Standard Webhooks vendor without a named wrapper works right now:

```ts
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](/docs/concepts/idempotency) | 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.

:::tip[Your provider isn't listed?]
If it's Svix-backed, the [generic Standard Webhooks
provider](/docs/providers/standard-webhooks) already handles it. Otherwise most
schemes are a dozen lines with `createHmacProvider` — see
[Build a custom provider](/docs/providers/custom).
:::
