A Cloudflare Worker gateway between the sushrutalgs.ai web and iOS apps and the AI backend, handling authentication, per-user daily usage limits and secure request forwarding so both clients talk to one trusted entry point, live in staging and production at roughly 14 milliseconds of added overhead.
sushrutalgs.ai has two clients, a Next.js web app and a native iOS app, and both need to reach the same AI backend. The obvious route, letting each client call the backend directly, means shipping the backend credential inside an App Store binary and writing the sign-in check and the paid usage limit twice, once in TypeScript and once in Swift. Two copies of a billing rule drift, and the copy inside a shipped iOS build cannot be corrected until the next review cycle. The gateway exists so there is exactly one place that knows who the user is, what they are still allowed, and how to talk upstream.
The hard part is not proxying, it is charging correctly for a response that has not finished yet. A user with a phone and a laptop open can fire two questions in the same instant: read the daily counter, decide, then write it back, and both requests pass, because both reads happened before either write. Answers also arrive as a server-sent-event stream, so once the first byte is on the wire the decision cannot be taken back, and a retry is not safe either: replaying a paid stream either charges twice or hands out an answer nobody paid for. All of this sits in front of every single request, so the budget for solving it is a few milliseconds.
The worker runs five stages in a fixed order: origin check, token verify, quota debit, body transform, forward. The ordering is the design. Nothing that costs money happens before the debit, and nothing that identifies the user travels past the transform.
The extra hop is real: about 14 milliseconds at p50, plus the Supabase round trip on the debit, added to every question anyone asks. Failing closed means a Supabase outage stops the product rather than quietly serving free answers, which is the trade taken on purpose for a paid product. The worker also stays deliberately thin, roughly 33 KiB gzipped, which rules out most of what a normal Node service would reach for: it runs on Hono and jose and very little else.
It is live in staging and production, serving both clients. Edge overhead sits at about 14 milliseconds p50 with JWT verification at p95 around 0.13 milliseconds, and a load run held 200 concurrent requests with zero errors and the fail-closed mapping verified. Staging deploys on every push while production is gated behind a release, so a web change cannot take the shipped iOS app down with it.
In numbers
The interesting decision in a gateway like this is never the proxying, it is the ordering — what happens before the meter turns and what happens after. Getting that sequence right, and proving it under 200 concurrent requests, is what makes 14 milliseconds a fair price rather than a hidden risk.