Coming from RevenueCat

The honest version first

RevenueCat vs Pithy is the comparison in full. A product is not an entitlement is the model you are moving to, resolving entitlements is what your gate does, and webhooks and replay is what keeps it current.

Buy Pro on iOS, be entitled on the web. That resolution is the whole product, and it is the same one 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 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.

What maps directly

RevenueCatHere
EntitlementEntitlement key — the thing your code checks
Offering / packageA catalog product
Store productA rail block on that product
Customer infoA subject — (subjectType, subjectId)
WebhooksRail webhooks, verified and deduped in your Worker

The modeling is the same, and it is the part worth keeping

pro_monthly and pro_annual are two products. Each is listed in three stores under three SKUs. Between them they grant one entitlement — pro.

app.get("/reports", requireAuth(), requireEntitlement("pro"), handler);

Nothing outside the catalog ever names a SKU. Add an annual plan, launch on a fourth store, rename a Play product id — that gate does not change, and neither does anything reading it.

If you already think this way, the migration is mostly moving a catalog you have already designed.

Five rails, configured

Apple, Google, Stripe, Lemon Squeezy and Paddle. Every rail is off until named, and each product carries a block per store it ships on.

What is different in practice

No SDK. Your client submits a receipt to your own route; there is no vendor library between you and the store.

You verify the webhooks. The kit’s signed-webhook strategy checks the signature over the exact received bytes with the timestamp inside the signed payload — and a UNIQUE (rail, providerEventId) insert is what catches a redelivery, because a verified delivery is not a new one.

You own the reconciliation. A Workflow you provision, not a service that reconciles for you.

No dashboard, unless you connect one. The hosted dashboard reaches into your Worker through a key you registered and can revoke — it holds no copy of your purchase data.

Migrating

Export your customer and transaction history, then decide what to import. Entitlement state is what your gates read, so it is the part that must be right on day one.

A grant of a key no product sells is refused unless you declare it in manualEntitlements — which is what turns a typo into a 400 rather than a row that grants nothing and that nobody notices for a month.

Run both in parallel while you verify. Nothing stops your Worker resolving entitlements from your own tables while RevenueCat still receives webhooks.

What you give up

Their store-quirk coverage — years of edge cases across five stores.

Their dashboards and charts.

A support contract.

What you get

The purchase history in your own database, joinable beside your own tables.

One indexed lookup per gated request, no cache — so a revocation is immediate rather than eventually consistent.

No vendor in the request path, and no per-transaction cut to a third party for resolving what your own database already knows.

ESC