Five payment rails — Apple, Google, Stripe, Paddle and Lemon Squeezy — resolving to one cross-rail entitlement, in your own Worker and your own D1.
@pithy-sh/payments
pithy add paymentsBuy Pro on iOS, be entitled on the web. Five rails in, one entitlement out, and every purchase row in a database you own.
A product is not an entitlement, and the catalog's keys are yours: rename a price in Stripe and your history does not rewrite itself.
What it sits on
Webhook verification runs in your Worker. Rail credentials live in the encrypted secret store, never in wrangler.jsonc. Reconciliation and retries run as Workflows, so a rail being briefly unreachable is not a lost purchase.
The honest bit
Cross-rail entitlement resolution is the product RevenueCat built a very good business on. Their SDKs, their store-quirk coverage and their dashboards are genuinely ahead of this package. If you want a hosted product with a support contract, buy theirs.
The honest difference is not the feature list. It is where the purchase history lives. RevenueCat is a hosted data plane holding your customers' transactions; this is five tables in a D1 you own, written by a Worker you deploy. Nothing here calls a Pithy-operated service, because there is not one.
If you build it yourself
Taking a card is a weekend. Reconciling five stores into one truthful answer is not.
Signature verification per rail, replay windows, out-of-order delivery, and idempotency — because every rail will send you the same event twice eventually.
Server-to-server notifications, receipt validation, sandbox versus production, grace periods, billing retries, and refunds that arrive as a different event shape entirely.
A customer who bought on iOS and signs in on the web is entitled. Getting that right means a resolution model, not a lookup.
What someone is entitled to during a failed payment, a scheduled downgrade, or the overlap while two subscriptions are live.
Renaming a price in a provider's dashboard must not rewrite what you already sold.
RevenueCat sells this as a hosted product and is genuinely good at it. The difference here is that the purchase history is five tables in your own D1.
pithy add paymentsComposes with
In the dashboard
Every product, purchase, subscription and entitlement your Worker holds. Manual grant and revoke arrive as admin routes behind the control-plane seam.
The dashboard is the admin interface for your own application: whatever this capability writes, your team can look up, check and act on from a browser. Reading is free, forever, with no time limit. Connect the project when you deploy.
Everything else
Each one composes the same way. Nothing you skip costs you anything.
Designed, not shipped
Written down, argued out, and not built yet. Each one links to the issue it is being designed in, so you can read the reasoning or disagree with it.
One command installs the package, wires its bindings into every environment your project declares, and runs its migrations.