Intro

Stripe Integration

How DevStride uses Stripe now that DevStride runs billing, what the Stripe webhook still does, and the ds stripe CLI: a read-only billing inventory and test-mode proofs of the Stripe behaviour billing relies on.

Stripe Integration

DevStride runs its own billing: it decides who is on trial, who pays, what they pay and who is locked. Stripe keeps the cards, processes the payments and stores the payment history. The ds stripe CLI (cli/commands/stripe.ts) wraps two commands: a read-only inventory of what Stripe holds for every customer, and test-mode proofs of the Stripe behaviour DevStride's billing relies on. It is a thin operational tool, not a sync engine — each command does one specific thing, and neither runs on a schedule.

Billing Inventory

ds -b stripe billing-inventory --out <directory outside the repository>

What It Does

Exports, read-only, everything Stripe holds for every customer beside DevStride's own view of the same customer — the census the billing migration is planned from, and the check run again before the old subscription code is deleted. Every Stripe call it makes is a list; it changes nothing, in Stripe or in DevStride.

It writes one row per billable organization to inventory.csv, plus the raw records it read as JSON Lines: organizations.jsonl, subscriptions.jsonl, customers.jsonl, unsettled-invoices.jsonl, pending-invoice-items.jsonl and catalogue.jsonl.

inventory.csv puts DevStride's stored status, seats and price beside Stripe's, compares seat counts three ways (stored, recomputed, Stripe), and carries renewal and trial dates, hand-extended trials, paused collection, the latest invoice status, scheduled changes in words, whichever payment method Stripe would actually charge, the invoice email, and a note column naming anything a person needs to look at.

The files are written readable by you alone, and the command will not follow a symlink or write into a directory that resolves inside the repository. In inventory.csv, any name or email beginning with =, +, - or @ carries a leading apostrophe so a spreadsheet cannot execute it as a formula.

When to run:

  • Taking a census of real billing state before changing anything
  • Re-checking that census before the old Stripe subscription code is removed

Prove Invoice Flow

ds -b stripe prove-invoice-flow

What It Does

Runs Stripe test-mode proofs of the behaviour DevStride's billing relies on, on the pinned Stripe SDK and API version rather than assumed, and prints PASS or FAIL for each claim. The groups cover direct card charges made through DevStride's own charging code (an off-session charge of the saved card, one payment per idempotency key, a decline read as the customer's to fix, finding a payment again by its metadata, and the receipt Billing History shows), staff refunds (a refund request made once however often it is replayed, the payment read back with its refund and the request that made it, and Stripe refusing more than is left), plus one-off invoices and subscription cancellation. The invoice groups document the design that direct card charging replaced and are kept as the record of what was measured.

It needs STRIPE_PROOF_KEY, a test-mode key, and refuses a live key outright. It is not kept in any secrets bundle, because the command writes; the STRIPE_SECRET_KEY already in your .env is a test-mode key, so STRIPE_PROOF_KEY="$STRIPE_SECRET_KEY" is enough. The customers it creates are deleted and its product and price archived at the end, even when a proof fails; a clean-up that fails makes the run fail and names what was left behind.

When to run: before relying on one of these Stripe behaviours in a change, or after a Stripe SDK or API version bump.

Next Steps