Skip to content
Webhooks SDK
Esc
↑↓navigate↵open⌘Jpreview
On this page

Stripe

Verify and handle Stripe webhooks — replay-safe out of the box, with zero-downtime secret rotation.

Create the endpoint in the Stripe dashboard, pass its signing secret, and handle events by name:

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.

Deliveries are signed over the timestamp and body together, so a replayed request is rejected on its own — you don’t need anything extra for replay protection.

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’s type (payment_intent.succeeded, …). Common event names autocomplete; any string routes.
  • event.timestamp — from the body’s created.
  • event.payload — the full Stripe event object; your data is at payload.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.

Last updated on September 1, 2026

Was this page helpful?