Stripe
HMAC over timestamp + body via Stripe-Signature — replay-safe, with first-class secret rotation.
Stripe signs each delivery with HMAC-SHA256 over {timestamp}.{body},
hex-encoded in the Stripe-Signature header (scheme family
2). The timestamp is inside the signed material,
so Stripe is replay-safe on its own.
import { createWebhookHandler } from 'webhooks-sdk'
import { stripe } from 'webhooks-sdk/stripe'
const handler = createWebhookHandler({
provider: stripe({ secret: process.env.STRIPE_WEBHOOK_SECRET! }),
on: {
'payment_intent.succeeded': async (event) => {
await fulfill(event.payload.data.object)
},
'customer.subscription.deleted': async (event) => {
await revoke(event.payload.data.object)
},
},
})
export const POST = handler.fetch
The secret is the whsec_… value shown when you create the endpoint in the
Stripe dashboard (or via the API). Each endpoint has its own — Connect and
Issuing endpoints too, so configure one provider per endpoint secret.
Options
| Option | Type | Default | |
|---|---|---|---|
secret |
string | string[] |
— | Endpoint signing secret(s). Pass an array during rotation. |
tolerance |
number |
300 |
Replay window in seconds. 0 disables it. |
Rotating secrets
Stripe keeps the previous secret valid for 24 hours after you roll it. Deploy with both during that window:
stripe({ secret: [process.env.STRIPE_SECRET_NEW!, process.env.STRIPE_SECRET_OLD!] })
The header can also carry multiple v1= signatures; all candidates are
checked against all secrets. See Secret rotation.
The envelope
event.id— Stripe’s event id (evt_…), the natural idempotency key.event.type— the body’stype(payment_intent.succeeded, …). Common event names autocomplete; any string routes.event.timestamp— from the body’screated.event.payload— the full Stripe event object; your data is atpayload.data.object.
Standalone & testing
import {
verifyStripeWebhook, // (raw, { secret, tolerance? }) — throws on failure
parseStripeWebhook, // (raw) — the envelope
signStripeWebhook, // (body, secret, timestamp?) — a valid header value, for tests
} from 'webhooks-sdk/stripe'
See Standalone verification and Testing.