Why I built a Dodo-first starter kit, and why this store runs on it
Stripe is closed to new Indian sellers charging internationally. So the billing layer got extracted from apps already taking money, and the store selling it is the demo.
There is a specific kind of stuck that does not show up in any "how to launch your SaaS" post. You have built the thing. It works. And you have no way to charge anyone for it, because you are in India and Stripe is not accepting new accounts for international payments from here.
You find this out late. Usually after the product is built, sometimes after you have written the checkout page. Every tutorial, every starter template and every model you ask assumes Stripe, because for a decade Stripe has been the default. The advice you get is to incorporate abroad, or to find someone who will let you use their account, or to wait.
Dodo Payments is the way out. It is open to sellers here, it handles international cards, and it is the merchant of record, which means global sales tax, receipts and refunds are its problem rather than yours. For a solo founder that last part matters more than it sounds: VAT registration across a dozen jurisdictions is the kind of work that quietly ends side projects.
So Dodo solves the account problem. Then you hit the second one.
The second problem: your agent has never seen this
Dodo is young. That is exactly why it is worth building on, and it is also why asking a coding agent to wire it up goes badly.
There is almost nothing about Dodo in any model's training data. So when you ask for a Dodo integration, you do not get a refusal or a shrug. You get confident, plausible, well-formatted Stripe code with the words changed. I have watched it produce all three of these:
- Header names that do not exist. Signature verification written against a scheme borrowed from a different provider. It compiles. It fails at runtime, in production, on a webhook you cannot easily replay.
- No replay guard. Payment providers retry deliveries. That is not an edge case, it is the documented behaviour. Without an idempotency check keyed on the event id, one retried delivery runs your fulfilment a second time. You find out when a customer emails about being charged twice, or when two invitations go out for one purchase.
past_duetreated ascancelled. This is the expensive one. When a card fails, the provider retries it over the next few days. During that window the customer is still a customer. Treatpast_dueas cancelled and you lock a paying user out of the product over a bank hiccup, on the exact day you most need them not to be annoyed with you.
Every one of those compiles. Every one passes tests the agent writes for itself, because it writes the tests against the same wrong mental model. Money goes missing anyway.
That is the gap. Not "starter kits save you time", which is a weak pitch in 2026 when an agent can generate a landing page in a minute. The pitch is narrower and, I think, actually true: the money path is the one part you should not generate, and it happens to be the part where Dodo has the least prior art for a model to draw on.
Extracted, not invented
I did not sit down and design a billing architecture for a product to sell. The order was the other way around.
The billing layer came out of paizy, which was charging
real cards on Dodo before this kit existed. The idempotency design, the
webhook_events table and the guard order came from getting the failure modes
above wrong first, in production, and fixing them. The provider adapter seam
came from client work where I wanted the state machine testable without a live
account, because you cannot write a good test suite against a payment provider
you have to call over the network.
So when the kit says the subscription state machine is dunning-aware, that is not a design principle. It is a bug I shipped once.
Extraction is also why the shape is what it is. Nothing outside
src/lib/billing/providers/dodo/ imports the Dodo SDK or knows what a raw
Dodo payload looks like, because that is what made the rest of it testable.
There are 81 tests, weighted heavily toward the webhook pipeline and the state
machine, and they run against fakes with no network and no account. You can
clone the repo and run npm test before you have signed up for anything.
Why this store runs on the kit
The obvious way to sell a starter kit is to build a marketing site on something else and describe the kit in prose. Plenty do. It is faster, and nobody can tell.
This store is a copy of the kit instead. The checkout route that is about to
charge you is src/app/api/checkout/route.ts from the repository you would be
buying — the kit's own checkout route and webhook pipeline, minus the sign-in
this store doesn't need. The webhook pipeline that records your purchase is
the one described three paragraphs up. The receipt email is the kit's receipt
template, QR code and all. The blog post you are reading is the kit's MDX
pipeline, and its Open Graph card came from the kit's image route.
The only thing removed is the accounts half. The store sells to anonymous buyers, so sign-in, the dashboard and the plan-gated surfaces are stripped out of this deployment. They are still in the product. Your copy ships with them.
Two reasons for doing it this way.
The first is that it is the only demo that cannot be faked. A screenshot proves nothing, a video proves slightly more, and a working checkout that takes your card and sends you a real receipt proves the thing itself. If the billing layer were bad you would find out during the purchase, which is a strong incentive to keep it good.
The second is selfish. Dogfooding means every rough edge in the kit is an edge I hit before a buyer does. Instantiating this store from the template was the buyer's first-run experience, start to finish: clone, install, strip what I did not need, rebrand, deploy. Everything that was annoying about it got fixed in the kit rather than written down as a known issue.
What it does not do
It does not guess your business logic and it does not try to be low-code. It ships the parts that are the same for almost every paid product: checkout, webhooks, subscription state, entitlements, sessions, transactional email, a blog and docs, and a test suite that tells you when you have broken the part that takes money.
The rest is yours to build, and by all means point an agent at it. That is the
intended workflow, and the repo carries an AGENTS.md and a bundled design
skill to make it go well. Let the agent build your product on top of a money
path a person already wrote, read twice, and covered with tests.
If you want the full inventory before you decide, it is in What's inside the Web Kit. If you want to know how delivery works, that is Getting access.