---
name: stripe-commerce-checkout
description: Build a Stripe Checkout endpoint with restricted keys, branded sessions, webhooks, and a test-first operating model.
license: MIT
tags: [stripe, commerce, checkout, payments, branding, webhooks]
agents: [claude-code, codex, cursor]
category: payments
metadata:
version: "1.1.0"
capabilities:
network: true
filesystem: readwrite
tools: [Bash, Read, Edit]
requires-secrets:
- name: STRIPE_SECRET_KEY
description: Server-side Stripe restricted or secret key, supplied through the deployment environment.
required: true
- name: STRIPE_WEBHOOK_SECRET
description: Webhook signing secret, supplied through the deployment environment when webhooks are enabled.
required: false
resources:
- path: story.md
type: file
- path: templates/cloudflare-pages-checkout.js
type: file
- path: templates/stripe-app.json
type: file
---Stripe Commerce Checkout
Use this skill for a server endpoint that creates Stripe-hosted Checkout Sessions. Start in test mode. Live products, prices, webhooks, and sessions require an explicit current-conversation instruction authorizing the specific live mutation.
Secrets and scope
Supply STRIPE_SECRET_KEY and, where applicable, STRIPE_WEBHOOK_SECRET through the host's secret manager or local environment. Never request them in chat, put them in a repository, pass them on a command line, or print them. Prefer a project-scoped restricted key over an account-wide key.
The Stripe CLI is useful for test-mode provisioning. Keep its credentials separate from application configuration; a CLI login key is not an application secret. Set environment variables in the deployment platform and use .dev.vars or an equivalent ignored local file for local work.
Build the endpoint
- Decide whether the offer is one-time, subscription, donation, or deposit.
- Accept only a documented
offerIdfrom the browser. Resolve its Stripe Price ID, product display data, quantity, and metadata from a server-side allowlist; never accept amounts, price IDs, product names, quantities, client reference IDs, or arbitrary metadata from the browser. - Start from
templates/cloudflare-pages-checkout.js; wire its fail-closed authenticated-user adapter to the application's server-side session, then configure its server-side offer map. It creates a Checkout Session usingSTRIPE_SECRET_KEYand returns{ id, url }for the newly created session. - Apply non-secret branding through
branding_settings. Session branding does not replace account-level legal, receipt, Link, or portal branding; verify those in the Stripe Dashboard. - For subscriptions, add a verified webhook and a user-return reconciliation path. The webhook remains the source of truth; reconciliation is only a fast path after a user returns from Checkout.
- Verify a new test-mode session after every endpoint or branding change. Existing session URLs are not a reliable test of a new deployment.
Webhooks and portal
Verify the Stripe signature using STRIPE_WEBHOOK_SECRET before changing entitlement or subscription state. Make handlers idempotent. On a Checkout return, retrieve the session server-side and verify that its client reference or metadata belongs to the authenticated user; never trust a browser-submitted customer or subscription ID.
Billing Portal branding is account-level, unlike Checkout Session branding. A distinct product may need a distinct Stripe account if the portal must have separate global branding.
Stripe App route
Stripe does not offer an API that mints new API keys. If installed accounts need a project-scoped key, use a reviewed Stripe App configuration such as templates/stripe-app.json, request the narrowest permissions possible, and let the account owner approve the install. Do not automate credential creation outside Stripe's supported flow.
Safety rules
- Default all mutations to test mode.
- Treat a configured live key as configuration, not authorization.
- Never expose a secret key or webhook secret in client code, logs, commits, or reports.
- Validate server-side ownership before granting access after Checkout.
- Report secret names and test evidence, never secret values.