Solutions

Mobile apps

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.

Get started All modules

What a phone actually needs

The mobile-shaped problems, answered.

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.

1

How do people sign in — including the way Apple insists on?

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.

2

How do they pay — on two stores and the web?

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.

3

Where do the photos and files go?

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.

4

How does a user tell you something is broken?

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.

5

Is there a game in it?

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.

6

And how do you get onto Google Play at all?

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

An app backend, in the order you would add it.

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.

terminal
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.

In practice

Buy on iOS, be entitled on the web.

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

The stores take their cut. Nobody else does.

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.

Start where it is cheapest to be wrong.

Add one capability, deploy it, and see the shape before you commit to the rest.