examples/storefront Public
id: payments
type: concept
owner: justin
component: payments
describes:
- workers/payments/src/index.ts
- workers/payments/src/stripe.ts
- src/payments.ts
reviewed: 2026-10-15
The payments Worker
storefront-payments (workers/payments) is the only Worker that talks to Stripe or holds its keys. It has two faces.
PaymentsService, for storefront-api
storefront-api reaches it through the PAYMENTS service binding, entrypoint PaymentsService. The binding is typed as the Payments interface in src/payments.ts, the same interface tests implement with FakePayments:
| Call | Used by | What it does |
|---|---|---|
createIntent({ order_id, amount_cents, currency, email }) |
checkout | creates a PaymentIntent with idempotency key order-<id> and returns its id and client secret |
cancelIntent(intent_id) |
expiry | cancels the intent; false if it already succeeded or is processing |
Service binding calls do not leave Cloudflare, and the entrypoint is not reachable from the internet. The Stripe adapter itself is workers/payments/src/stripe.ts.
The webhook, for Stripe
Its fetch handler serves POST /stripe/webhook and nothing else ([[payment-webhook]]). It settles orders through storefront-api's OrdersService over the ORDERS binding, because only storefront-api writes to D1 ([[0006-one-writer-for-the-database]]).
So the two Workers bind each other: storefront-api calls payments to charge, payments calls storefront-api to record the result. Deploy order matters only when an interface changes: add a method on the side being called first.
Secrets
STRIPE_SECRET_KEY and STRIPE_WEBHOOK_SECRET, set with npx wrangler secret put -c workers/payments/wrangler.jsonc. Rotating the secret key means redeploying nothing else. Why the keys moved here is in [[0010-payments-worker]].