Stripe Integration (CLI-first workflow)
Use the Stripe CLI to develop and test Cascades billing flows locally — events, webhooks, DAG templates, and verification.
Use the Stripe CLI to develop and test billing workflows locally.
Billing authority: Stripe is the source of truth for subscriptions and invoices. Cascades does not manage authoritative billing state—it reacts to signed webhook events and updates application records (user subscription fields, tiers, period end) accordingly.
This aligns with Cascades’ event-driven execution model:
- Trigger events (
stripe trigger …) - Ingest via
/api/webhooks/stripe - Process through DAGs (catalog template + workers)
- Verify execution (runs, logs, proofs)
Hosted billing is optional — see Stripe Billing for product surfaces (/pricing, /dashboard/billing). This page focuses on CLI ↔ config ↔ webhook ↔ workflow template.
1. Create products and prices
Canonical billable tiers live in config/plan-definition.ts (USD amounts, Stripe catalog names, public price env keys). npm run pull-billing-catalog refreshes config/stripe-products.snapshot.json for offline drift checks (npm run verify:entitlements-drift).
Automated (recommended): with STRIPE_SECRET_KEY set,
npm run stripe:catalog # dry-run
npm run stripe:catalog -- --applyPaste printed NEXT_PUBLIC_STRIPE_*_PLAN_ID lines into env — Products carry metadata.cascades_tier, and each Price carries metadata.cascades_tier + metadata.cascades_interval so webhook payloads map tiers without relying only on env-configured price_id hashes.
Manual Stripe CLI example:
stripe products create --name="Pro Plan"
stripe prices create \
--product=prod_xxx \
--unit-amount=2000 \
--currency=usd \
--recurring=interval:monthThen bind Stripe price IDs to the app’s public env vars (used by checkout UI):
NEXT_PUBLIC_STRIPE_STARTER_MONTHLY_PLAN_ID,NEXT_PUBLIC_STRIPE_STARTER_YEARLY_PLAN_IDNEXT_PUBLIC_STRIPE_PRO_MONTHLY_PLAN_ID,NEXT_PUBLIC_STRIPE_PRO_YEARLY_PLAN_IDNEXT_PUBLIC_STRIPE_BUSINESS_MONTHLY_PLAN_ID,NEXT_PUBLIC_STRIPE_BUSINESS_YEARLY_PLAN_ID
These correspond to pricingData[].stripeIds in config/subscriptions.ts — catalog rows → checkout.
Optional sanity check:
npx tsx scripts/validate-stripe-prices.ts2. Local webhook development
Forward sandbox events to your local handler (adjust host/port to match NEXT_PUBLIC_APP_URL):
stripe listen \
--events checkout.session.completed,customer.subscription.updated,customer.subscription.deleted,invoice.payment_succeeded \
--forward-to localhost:3000/api/webhooks/stripeThe CLI prints a signing secret (whsec_…). Set STRIPE_WEBHOOK_SECRET to that value while developing — this is how Stripe forwards events locally with verifiable signatures.
3. Trigger execution flows
Simulate a completed checkout without a real card:
stripe trigger checkout.session.completedWatch your stripe listen terminal and Cascades logs — the webhook route should return 200 after handling supported event types.
4. Cascades mapping — Stripe event → system behavior
Today, POST /api/webhooks/stripe verifies Stripe-Signature, then applies subscription fields on the User row for events such as:
| Stripe event | Cascades effect (summary) |
|---|---|
checkout.session.completed | Attach subscription + customer + price + period end when metadata includes userId |
invoice.payment_succeeded | Refresh subscription state on renewals / changes (skips first invoice duplicating checkout) |
customer.subscription.updated | Update subscription + period |
customer.subscription.deleted | Clear subscription fields |
That path is database-backed entitlement provisioning — the DAG template below is how you model the same story inside workflow graphs.
Workflow template: Stripe subscription provisioning
Bundled catalog id: wf-stripe-subscription-provisioning
Conceptual DAG:
Stripe webhook envelope
→ Dedupe / idempotency (replay guard)
→ Validate billing-shaped event
→ Provision access (simulated tool step)
→ Record proof-friendly terminal
Set stripeEvent.duplicate: true in sample context to exercise the replay / skip provisioning branch.
Open Workflows → run from the catalog, or see the definition in lib/workflows/preset-library.ts. Sample context for “Run with sample inputs” includes stripeEvent.type: checkout.session.completed.
Where this becomes more than instructions
- Dashboard → Integrations → Deployment → Stripe shows webhook readiness and (in dev) a Trigger test event control that mirrors
stripe trigger checkout.session.completed. - Docs ↔ product: keep CLI commands and env vars next to the routes they feed — that is the integration surface.
Related
- Stripe Billing — runtime surfaces and validation checklist
- Webhooks — inbound HTTP patterns
- Stripe CLI — use the CLI — upstream reference