Mobile is where backend kits reveal that they were built for the web. Bearer tokens are an afterthought, store billing is somebody else's product, sign-in with Apple is a checkbox nobody implemented, and nothing at all helps with the store obligations standing between you and production. Every one of those is a capability here.
What a phone actually needs
Not a web backend with a mobile SDK bolted to the side. These are the parts that only exist because the client is an app on someone's phone.
Sign in with Apple is here because the App Store requires it: ship any third-party sign-in and Apple's own has to be offered alongside it. Google sits next to it, and magic link and email OTP cover everyone who wants neither.
Both OAuth rails run over PKCE with deep-link redirects, which is where mobile auth usually breaks — the universal-link cases where the browser hands control back to the wrong app, or to none. Sessions are token-first by design: short-lived access tokens, rotated refresh tokens in secure device storage, and a device registry so you can revoke one handset without signing out the rest. There is no email and password, on purpose.
Five rails, one entitlement. Apple through StoreKit and Google through Play Billing for in-app purchase, then Stripe, Paddle and Lemon Squeezy for the same product sold on your website.
The load-bearing distinction is that a product is not an entitlement. pro_monthly and pro_annual are two products, listed in three store catalogs under three different SKUs, granting one entitlement — pro. Your gate names the entitlement, so adding an annual plan or launching on a fourth store changes the catalog and nothing else.
Which is why someone who subscribes on their iPhone is entitled in a browser on their laptop, and why the receipt that proves it never leaves your D1.
Uploads land in your own R2 bucket with an owner, a quota and a lifecycle — not in a vendor's bucket you rent access to. For images, video, audio and documents there is a media capability that tracks and enriches them; for everything else, general file storage with the same ownership model.
In-app reports from a signed-in user land in the same inbox as email, in your own D1, classified on your own Workers AI binding — and already linked to the account, the purchases and the session behind them. You are not reading a ticket that says "it crashed" from an address you cannot place.
If the app has anything turn-based in it — a duel, a board, a table — the same authoritative sessions the games page describes run on the same Worker, with the phone as just another client. Async play is the mobile-native shape anyway: a Durable Object holding the state between turns costs nothing while nobody is taking one.
A new personal developer account owes Google a closed test before it may go to production: twelve testers, opted in, for fourteen continuous days. Lose one on day nine and the clock effectively restarts. The Play console does not show you a countdown, a roster health check, or who quietly opted out.
The testers capability holds the roster, sends and tracks the invitations, and answers the only question that matters — how many days are left, and is anybody about to break the streak.
What that composes to
Every command installs a package, writes its block into pithy.config.ts, wires the bindings and runs its migrations. Only the payments provision step touches your Cloudflare account.
pithy init # the Worker, its config, per-env wrangler.jsonc
bun install
pithy add secrets # required by payments; every rail's credentials
pithy add auth # Apple, Google, magic link, email OTP
pithy add payments # StoreKit, Play Billing, Stripe, Paddle, Lemon Squeezy
pithy add media # images, video, audio, documents in your R2
pithy add support # in-app reports and mail, in one inbox
pithy payments provision # deploys the reconciliation Workflow
pithy migrate
bun run dev # http://localhost:8787
Receipts, entitlements, uploads and support threads all land in a D1 and an R2 on your own account. There is no Pithy-operated service in the path.
What you would compose
Passwordless sessions, mobile and web both first-class. Magic link, email OTP, Google, Apple.
pithy add auth
Language for your app — negotiated per request, rendered through one seam. No tables, no bindings, no error codes of its own.
pithy add i18n
A per-user balance for your app's economy — chips, gold, gems, credits. Correct by construction.
pithy add ledger
Store, track and enrich images, video, audio and documents. Config picks the backend.
pithy add media
Authoritative sessions on Durable Objects. The server holds what no client can be trusted with.
pithy add multiplayer
Five payment rails resolving to one cross-rail entitlement, in your own Worker and your own D1.
pithy add payments
General file storage in your own R2 bucket, with an owner, a quota, and a link you can take back.
pithy add storage
An inbox that lands mail in your own D1, classifies it on your own AI, and knows who sent it.
pithy add support
The roster, the invitations and the fourteen-day clock Google Play makes you run.
pithy add testers
In practice
Auth is token-first by design: short-lived access tokens with rotated refresh tokens in secure device storage, OAuth over PKCE with deep-link redirects. Sign in with Apple is there because the App Store will require it.
A purchase through StoreKit and a purchase through Play Billing both resolve to the same entitlement as a card payment on your website — so a customer who subscribed on their phone is entitled in the browser, and the receipt never leaves your D1.
And before any of that ships on Android, a new personal developer account owes Google a closed test: twelve testers, opted in for fourteen continuous days. Nothing in the Play console tells you where you stand. The testers capability does.
What it costs
Apple and Google take their commission, and no backend changes that. What Pithy removes is the layer that would otherwise sit between you and the receipt taking a further percentage or a monthly fee for holding your purchase history.
Everything else is Cloudflare usage — a Worker, a D1 and an R2 bucket.
Cloudflare sets and changes these prices; their pricing page is the authority, not this one. Pithy itself is free and always will be.
Add one capability, deploy it, and see the shape before you commit to the rest.