Supported Providers
All 9 built-in provider adapters — signature scheme, headers, and import for each.
Every provider adapter implements the same interface: verify the signature, check the timestamp tolerance, and parse the body into a typed event. Import the one you need from @hooksentinel/core and pass it to createWebhookHandler.
import { createWebhookHandler, stripe } from '@hooksentinel/core';
const handler = createWebhookHandler({
provider: stripe({ secret: process.env.STRIPE_WEBHOOK_SECRET! }),
onEvent: async (event) => { /* ... */ },
});Provider table
| Provider | Import | Signature scheme | Header(s) | Config |
|---|---|---|---|---|
| Stripe | stripe() | HMAC-SHA256 over t=<ts>,v1=<body> | Stripe-Signature | secret |
| GitHub | github() | HMAC-SHA256 over raw body | X-Hub-Signature-256 | secret |
| Shopify | shopify() | HMAC-SHA256 (base64) over raw body | X-Shopify-Hmac-Sha256 | secret |
| Standard Webhooks | standardWebhooks() | HMAC-SHA256, standardwebhooks.com spec | webhook-id, webhook-timestamp, webhook-signature | secret |
| Slack | slack() | HMAC-SHA256 over v0:<ts>:<body> | X-Slack-Signature, X-Slack-Request-Timestamp | signingSecret |
| Discord | discord() | Ed25519 signature | X-Signature-Ed25519, X-Signature-Timestamp | publicKey |
| Twilio | twilio() | HMAC-SHA1 over URL + sorted params (base64) | X-Twilio-Signature | authToken, url |
| Paddle | paddle() | HMAC-SHA256 over raw body | Paddle-Signature | secret |
| Generic | generic() | Configurable — HMAC-SHA256/SHA1 or Ed25519, custom header names | Configurable | secret, headerName, algorithm |
All HMAC-based providers default to a 5-minute (300s) timestamp tolerance where the provider includes a timestamp; override with the tolerance option in seconds. See timestamp_out_of_tolerance for what happens outside that window.
Stripe
import { stripe } from '@hooksentinel/core';
stripe({
secret: process.env.STRIPE_WEBHOOK_SECRET!,
tolerance: 300, // optional, seconds — default 300
});Events are typed against Stripe's Event union. event.type narrows event.data.object.
GitHub
import { github } from '@hooksentinel/core';
github({
secret: process.env.GITHUB_WEBHOOK_SECRET!,
});Events are typed by the X-GitHub-Event header (push, pull_request, issues, workflow_run, ...). GitHub does not send a timestamp, so replay protection relies on deduplication rather than tolerance windows — see Idempotency.
Shopify
import { shopify } from '@hooksentinel/core';
shopify({
secret: process.env.SHOPIFY_WEBHOOK_SECRET!,
});Events are typed by the X-Shopify-Topic header (orders/create, orders/updated, app/uninstalled, ...).
Standard Webhooks
Implements the open Standard Webhooks specification used by a growing set of providers (Clerk, Resend, and others that adopt the spec).
import { standardWebhooks } from '@hooksentinel/core';
standardWebhooks({
secret: process.env.WEBHOOK_SIGNING_SECRET!,
});Slack
import { slack } from '@hooksentinel/core';
slack({
signingSecret: process.env.SLACK_SIGNING_SECRET!,
});Handles both Events API payloads and interactive component payloads, including the url_verification handshake challenge.
Discord
Discord signs with Ed25519 rather than HMAC — hooksentinel handles the different verification primitive transparently.
import { discord } from '@hooksentinel/core';
discord({
publicKey: process.env.DISCORD_PUBLIC_KEY!,
});hooksentinel also responds to Discord's PING interaction type automatically so your onEvent only sees real events.
Twilio
Twilio's signature is computed over the full request URL plus sorted form parameters, not a raw JSON body, so pass the externally-visible URL your webhook is registered at.
import { twilio } from '@hooksentinel/core';
twilio({
authToken: process.env.TWILIO_AUTH_TOKEN!,
url: 'https://api.example.com/webhooks/twilio',
});Paddle
import { paddle } from '@hooksentinel/core';
paddle({
secret: process.env.PADDLE_WEBHOOK_SECRET!,
});Supports Paddle Billing's v2 signature format.
Generic
For providers without a built-in adapter, generic() covers the common signature shapes without writing a full adapter.
import { generic } from '@hooksentinel/core';
generic({
secret: process.env.CUSTOM_WEBHOOK_SECRET!,
headerName: 'X-Custom-Signature',
algorithm: 'sha256', // 'sha256' | 'sha1' | 'ed25519'
});generic() events are typed as unknown by default — narrow them yourself, or wrap the result with your own Zod schema in onEvent.
Last updated on