Skip to content
Webhooks SDK
Esc
navigateopen⌘Jpreview
On this page

One route, many providers

Serve Stripe, GitHub, and everything else from a single endpoint with WebhookRouter.

Once you’re past one or two integrations, per-provider routes stop scaling. WebhookRouter serves any number of providers from one endpoint:

import { WebhookRouter } from 'webhooks-sdk'
import { stripe } from 'webhooks-sdk/stripe'
import { github } from 'webhooks-sdk/github'

const router = new WebhookRouter({
  providers: {
    stripe: stripe({ secret: process.env.STRIPE_SECRET! }),
    github: github({ secret: process.env.GITHUB_SECRET! }),
  },
})

router.on('stripe', 'charge.refunded', handleRefund)
router.on('github', 'push', handlePush)

Mount it on a catch-all route:

export const POST = router.fetch

Now POST /api/webhooks/stripe verifies and dispatches with the Stripe provider, POST /api/webhooks/github with the GitHub one.

How the provider is chosen

By default the router takes the provider key from the last path segment of the request URL. Override with resolve when your URLs don’t follow that shape:

const router = new WebhookRouter({
  providers: { /* … */ },
  resolve: (request) =>
    new URL(request.url).searchParams.get('source') ?? undefined,
})

A request that resolves to no known provider gets a 404 with { error: 'unknown_provider' } — nothing is verified or dispatched. (router.on() with an unknown key throws immediately instead, so a typo fails at startup, not at delivery time.)

Shared options

Secrets, tolerances, and modes are set where each provider is constructed. Cross-cutting concerns live on the router and apply to every provider:

const router = new WebhookRouter({
  providers: { /* … */ },
  idempotency: memoryIdempotencyStore(), // one store, keys namespaced per provider
  onEvent: (event) => log(event.provider, event.type),
  onError: (error) => report(error),
})

onEvent, onUnhandled, onError, tolerance, and now behave exactly as they do on createWebhookHandler. Idempotency keys are prefixed with the provider id, so one store safely serves all providers.

Was this page helpful?