Rebasely Beta: data may be purged

examples/storefront Public

Markdown · 2.1 KiB · at b748afa

id: payment-webhook
type: concept
owner: justin
component: stripe-webhook
describes:
  - workers/stripe-webhook/src/**
reviewed: 2026-10-09

The payment webhook

An order is paid when Stripe says so, never when the browser says so. Stripe sends events to https://<stripe-webhook host>/stripe/webhook, and the storefront-stripe-webhook Worker turns them into order changes.

What it does

  1. Verifies the stripe-signature header against STRIPE_WEBHOOK_SECRET with Web Crypto. A bad or missing signature gets a 400 and changes nothing.
  2. For payment_intent.succeeded, calls OrdersService.markPaid(order, intent) on storefront-api. The order id comes from the intent's metadata, which checkout set ([[checkout]]).
  3. For payment_intent.canceled, calls OrdersService.cancel(order), which puts the stock back.
  4. Answers 200 to everything else, including events for intents without an order_id, so Stripe stops retrying them.

The Worker has no database binding. It reaches orders only through the service binding ORDERS ([[0006-one-writer-for-the-database]]).

Retries and repeats

Stripe delivers each event at least once and retries anything that does not get a 2xx. Both calls are safe to repeat:

  • markPaid only moves an order from pending_payment to paid, and only when the intent id matches the one stored at checkout.
  • cancel puts stock back in the same batch that cancels the order, and only while the order is pending.

If OrdersService throws, the webhook answers 500 and Stripe tries again later.

A payment for a cancelled order

If an order was cancelled and its payment still succeeds, markPaid leaves the order cancelled and the Worker logs payment for a cancelled order, refund it as an error. Expiry cancels the intent before the order ([[checkout]]), so this needs an order cancelled some other way; the log line is there to search for if it happens.

Local testing

stripe listen --forward-to localhost:8788/stripe/webhook prints a webhook secret for .dev.vars and forwards test-mode events. Run the Worker with npx wrangler dev -c workers/stripe-webhook/wrangler.jsonc --port 8788 next to storefront-api.