npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@beignet/provider-webhooks-stripe

v0.0.34

Published

Stripe webhook verifier provider for Beignet

Readme

@beignet/provider-webhooks-stripe

Stripe webhook verifier provider for Beignet applications.

This package adapts Stripe's official webhook signature verification to @beignet/core/webhooks. Use it when an app receives Stripe events outside the payments port, or when you want your billing webhook definition to use the generic Beignet webhook route adapter.

For standard Beignet billing flows, prefer @beignet/provider-payments-stripe with createPaymentWebhookRoute(...). That path installs ctx.ports.payments, verifies through the payments port, and is what beignet make payments generates.

Install

bun add @beignet/provider-webhooks-stripe stripe @beignet/core

Configure

Set the endpoint signing secret for the webhook endpoint you are receiving:

STRIPE_WEBHOOK_SECRET=whsec_...

Dashboard endpoint secrets, live-mode secrets, and local Stripe CLI secrets are different values. For local testing, run:

stripe listen --forward-to http://localhost:3000/api/webhooks/stripe

Then set STRIPE_WEBHOOK_SECRET to the whsec_... printed by the Stripe CLI for that local app process.

beignet doctor --strict checks STRIPE_WEBHOOK_SECRET when this package is installed. The package is optional by registration metadata because verifier packages are wired at the route/server boundary instead of installed in server/providers.ts; remove the dependency if the app is not using a generic Stripe webhook endpoint.

Installed ports

This package does not install Beignet lifecycle ports. It exports createStripeWebhookVerifier(...), which you pass to createWebhookRoute(...) or verifyWebhook(...) at the route/server boundary.

It does not expose a provider escape hatch; pass a custom Stripe client when the app needs provider-specific SDK configuration.

Instrumentation

This verifier package does not record provider instrumentation directly. createWebhookRoute(...) owns the route response, and your handler should record app-specific audit entries, jobs, outbox messages, or custom devtools events after verification when those side effects matter.

Define a webhook catalog

Keep the event catalog near the feature that owns the workflow:

// features/integrations/webhooks.ts
import { defineWebhook } from "@beignet/core/webhooks";
import { z } from "zod";

type StripeWebhookPayload = {
  id: string;
  object: string;
};

const stripeEventSchema = z.custom<StripeWebhookPayload>(
  (value): value is StripeWebhookPayload =>
    typeof value === "object" &&
    value !== null &&
    typeof (value as { id?: unknown }).id === "string" &&
    typeof (value as { object?: unknown }).object === "string",
);

export const stripeWebhook = defineWebhook("integrations.stripe", {
  provider: "stripe",
  events: {
    "customer.created": stripeEventSchema,
    "charge.dispute.created": stripeEventSchema,
  },
});

The verified Beignet event has provider: "stripe" and uses the Stripe event.data.object as event.payload. The complete Stripe event stays available as event.raw, and account, livemode, request, and API version details are copied into event.metadata.

Expose a Next.js route

Use the generic Beignet webhook route adapter so the raw body is preserved for Stripe signature verification. Wire the provider verifier at the route/server boundary so feature webhook catalogs stay provider-runtime free. beignet lint enforces this boundary: contract-reachable feature code cannot import @beignet/provider-* packages, so the verifier attaches through the verify option of createWebhookRoute(...) instead of the webhook definition:

// app/api/webhooks/stripe/route.ts
import { createWebhookRoute } from "@beignet/next";
import { createStripeWebhookVerifier } from "@beignet/provider-webhooks-stripe";
import { stripeWebhook } from "@/features/integrations/webhooks";
import { handleStripeWebhookUseCase } from "@/features/integrations/use-cases";
import { env } from "@/lib/env";
import { getServer } from "@/server";

export const runtime = "nodejs";

const stripeWebhookVerifier = createStripeWebhookVerifier({
  secret: () => env.STRIPE_WEBHOOK_SECRET,
});

export const { POST } = createWebhookRoute({
  server: getServer,
  webhook: stripeWebhook,
  verify: ({ input }) => stripeWebhookVerifier.verify(input),
  handle: async ({ ctx, event }) => {
    await handleStripeWebhookUseCase.run({
      ctx,
      input: event.payload,
    });

    return {
      status: 200,
      body: { received: true },
    };
  },
});

Handlers should key idempotency on event.id, update app-owned state inside a transaction, and push durable follow-up work through outbox, jobs, listeners, or notifications after verification.

Generic webhook routes reject verified event types that are not listed in the catalog by default. Set allowUnknownEvents: true only when a broad Stripe endpoint should acknowledge valid event types the app does not handle.

export const { POST } = createWebhookRoute({
  server: getServer,
  webhook: stripeWebhook,
  verify: ({ input }) => stripeWebhookVerifier.verify(input),
  allowUnknownEvents: true,
  handle: async ({ event }) => {
    if (event.type !== "customer.created") {
      return { status: 200, body: { ignored: true } };
    }

    return { status: 200, body: { received: true } };
  },
});

Custom clients

Pass an existing Stripe client when your app already owns SDK configuration:

import Stripe from "stripe";
import { createStripeWebhookVerifier } from "@beignet/provider-webhooks-stripe";

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY ?? "");

export const verifier = createStripeWebhookVerifier({
  client: stripe,
  secret: () => process.env.STRIPE_WEBHOOK_SECRET,
});

You can also set a custom signature header or Stripe timestamp tolerance:

createStripeWebhookVerifier({
  secret: () => process.env.STRIPE_WEBHOOK_SECRET,
  signatureHeader: "stripe-signature",
  tolerance: 300,
});

Relationship to payments

@beignet/provider-payments-stripe adapts Stripe to Beignet's PaymentsPort and includes payment-specific operations such as checkout sessions, billing portal sessions, refunds, and payment webhook conversion.

Use this package for the generic inbound webhook primitive. It does not create checkout sessions, manage subscriptions, or install ctx.ports.payments.

Failure behavior

  • Missing or invalid Stripe signatures throw WebhookVerificationError values that createWebhookRoute(...) maps to 400 responses.
  • Handler failures return 500 from createWebhookRoute(...) so Stripe can retry.
  • Verified duplicate events should be handled idempotently by app code.
  • Long-running work should be recorded through Beignet jobs, outbox delivery, listeners, or notifications instead of blocking the route.

Local and tests

Use a fake verifier for use-case tests and test createWebhookRoute(...) with signed requests when verification behavior matters. Use the Stripe CLI for local end-to-end delivery tests and remember that CLI endpoint secrets differ from dashboard endpoint secrets.

Deployment notes

Use endpoint-specific whsec_... secrets per deployed route. Prefer @beignet/provider-payments-stripe and createPaymentWebhookRoute(...) for standard billing flows; use this generic verifier for non-payment Stripe event catalogs.