Skip to main content
Stripe cannot reach a sandbox, so pre.dev receives every Stripe event for your workspace and relays it to your app. There is no endpoint to register and no signing secret to copy.

Where events arrive

pre.dev posts each event to POST /api/stripe/webhook on your app, at the live sandbox URL while you build and at the deployed URL once deployed. Mount your handler on exactly that path. The request looks exactly like one from Stripe: a JSON event body and a Stripe-Signature header. Verify it with the Stripe SDK and STRIPE_WEBHOOK_SECRET, which is this project’s own secret.
The handler must read the raw request body. A JSON body parser that runs first changes the bytes and the signature check fails.

Which events

Every event Stripe emits for your workspace’s account is relayed. Handle the ones you need and return 2xx for the rest. Typical ones for subscriptions are checkout.session.completed, invoice.paid, invoice.payment_failed, and customer.subscription.updated or deleted.

Retries and pausing

A delivery that fails with a timeout or a 5xx is retried with backoff for about 45 minutes. A 4xx other than 408 or 429 is not retried. If your app answers 404 at the webhook path three times in a row, deliveries to that project pause. They resume the next time the app makes a Stripe call through pre.dev, so mounting the route and reloading is enough.

Do not register an endpoint

Calling stripe.webhookEndpoints.create through the built-in key returns a 400 that explains delivery is built in. Your own Stripe dashboard is not involved while in test mode.

Testing a flow end to end

  1. Start a Checkout session in your app and pay with 4242 4242 4242 4242.
  2. Watch the server log for checkout.session.completed arriving at /api/stripe/webhook.
  3. Confirm your handler did its work, for example a row marked paid.
The build agent does exactly this before it reports a payments feature done.