Your app's backend,
already built.

Ship the iOS/Android app — the backend is done. Apple, Google and passwordless sign-in, a clean bearer-token JSON API, user profiles and per-user data, plus an operator console to run it. Subscriptions wired for in-app plans, on plain PHP and SQLite.

1 dependency No build step Built for AI agents Stripe + SES ready
Mobile app backend

Tap sign in. The backend does the rest.

Apple, Google and passwordless sign-in, a bearer-token JSON API, profiles and per-user data — the whole backend your app needs, on plain PHP and SQLite. No Firebase bill, no SDK to babysit.

  • Provider id_tokens verified server-side (JWKS)
  • Bearer app tokens — hashed, revocable per device
  • A real JSON API over per-user data to clone
EVERYTHING YOUR APP'S BACKEND NEEDS

Sign-in, a JSON API, profiles and data — already wired.

Point your iOS or Android app at one PHP backend. It verifies Apple/Google/passwordless sign-in, hands the app a bearer token, and serves a clean JSON API over per-user data. No Firebase bill, no SDK to babysit.

Native Apple & Google sign-in, verified

The app sends the provider id_token; the backend verifies its RS256 signature against Apple/Google JWKS before trusting a single claim, then finds-or-creates the user through the same identity-linking path the web login uses. No client claim is taken on faith.

Passwordless email, no password store

app_request_code emails a 6-digit code; app_verify_code checks it and returns a token. It reuses the exact login-code mechanism the website uses, so there is one auth pipeline to reason about and no passwords anywhere in the database.

Bearer app tokens, hashed not stored

Sign-in mints a long random at_ token returned once. Only a peppered HMAC-SHA256 hash and the device label hit the database; last_used_at is stamped per call, and any device can be revoked. A leaked DB hands an attacker nothing usable.

A real JSON API, not a stub

app_me, app_profile_update, app_logout and a full app_items CRUD ship as working, per-user-scoped endpoints with consistent JSON envelopes, status codes and validation. Clone app_items into your own models and keep the shape.

Per-token rate limits, 429 + Retry-After

Each app token is throttled by a fixed-window limiter in SQLite — 300 requests per 60s out of the box, one env var to change. Over the line returns 429 with a Retry-After header. No Redis, no sidecar.

An operator console to run it

The member app is a backend console: app users with their auth provider and last-seen, the live app data, which sign-in methods are enabled, issue/revoke app tokens, and a copy-paste cURL + Swift quickstart. Subscriptions are wired for in-app plans.

Sign in once, call the API

Apple token in, an app token out — then real JSON.

Your app sends the provider id_token; the backend verifies its signature, finds-or-creates the user, and returns a bearer app token the app stores. Every call after that is one header.

api.yoursite.com/api.php
# 1. Sign in: the app posts the Apple/Google id_token.
curl -X POST https://api.yourapp.com/api.php?action=app_auth_apple \
  -d '{"id_token":"eyJ...","nonce":"a1f3","device":"iPhone 15"}'
{ "ok": true, "token": "at_9f2a…",
  "user": { "id": 51, "email": "ada@app.dev" } }
# 2. Every call after: one Authorization header.
curl https://api.yourapp.com/api.php?action=app_items_list \
  -H "Authorization: Bearer at_9f2a…"
{ "ok": true, "items": [ { "id": 12, "title": "Hello" } ] }
A mobile backend, by the numbers

Auth, tokens and data — wired before you open Xcode

Every figure here is how the backend actually behaves the moment you deploy it — not a sales chart. It's a template.

3 sign-in methods your app can call: Apple, Google, and passwordless email codes
0 passwords or raw tokens stored — only peppered HMAC-SHA256 hashes touch the database
300 app-API requests per 60s window per token, out of the box — one env var to change
1 header Authorization: Bearer is the entire auth contract for every app call after sign-in
FROM TAP-TO-SIGN-IN TO YOUR JSON

What happens between the app and the database.

Every request runs a short, readable path: verify the caller, resolve the token, run your code. It is plain PHP you can read top to bottom — no framework, no managed-auth dashboard.

1

Verify the provider, not the client

A native id_token arrives with no trusted server channel behind it, so the backend fetches the provider JWKS, verifies the RS256 signature, then checks issuer, audience, expiry and the app-supplied nonce. Only a verified email is ever linked to an account.

2

Mint a token the app keeps

On success the backend issues an at_ token and returns it once. The app stores it in the Keychain / Keystore and sends it as Authorization: Bearer on every later call. The server keeps only a peppered hash, so the plaintext never sits in the database.

3

Resolve the token, then do the work

require_app_user() hashes the incoming bearer token, matches it to its owner in one query, stamps last_used_at and applies the per-token rate limit — a bad or revoked token is a clean 401 before any work happens. No session, no CSRF; this is the app surface.

4

Serve per-user data, scoped by default

Every app_items query is filtered by the authenticated user id, so one account can never read or delete another's rows. Clone the resource, rename it, and your API answers in the same JSON shape the Stripe webhooks and admin console already speak.

THE WHOLE STACK

Your mobile app's whole backend, on one core

Apple/Google/passwordless sign-in, id_token verification, bearer app tokens and a JSON API over per-user data all wire into one core. Point your iOS/Android app at it and ship.

App backend JSON · bearer Apple·Google·email id_token verify Bearer app tokens Revoke per device Per-token limits JSON app API Per-user app data Backend admin app App backend JSON · bearer Apple·Google·email Per-token limits id_token verify JSON app API Bearer app tokens Per-user app data Revoke per device Backend admin app
Superadmin, not a spreadsheet

A real admin console — have a poke around.

Every install ships with this. Search users, replay webhooks, inspect billing and revoke keys — server-rendered, access-gated, no second app.

app.yoursaas.com/admin superadmin
MRR$0▲ 12%
Active subs0▲ 6
Credits today0spent
Signups · 7d0▲ 18%
UserPlanStatusJoined
ada@example.comProactive2d ago
grace@example.comScaleactive5d ago
linus@example.comStarterpast due3w ago
margaret@example.comProactive1mo ago
blocked@example.comFreeblocked1mo ago
processedinvoice.paidevt_1Q8x…a3
processedcustomer.subscription.updatedevt_1Q8w…f1
processedcheckout.session.completedevt_1Q8w…7c
retryinginvoice.payment_failedevt_1Q8v…02
refundedcharge.refundedevt_1Q8u…9d
curl -H "Authorization: Bearer ss_live_••••" \
     https://app.yoursaas.com/api.php?resource=notes

{
  "ok": true,
  "data": [ "note_18f2", "note_18f9" ],
  "rate_limit": "58/60",
  "credits_left": 1840
}
From download to charging cards

Live on a real VPS in an afternoon.

01

Unzip & copy

copy a template folder

02

Install & connect

composer install · Stripe + SES

03

Ask your agent

rebrand · plans · run doctor

04

Deploy & charge

NGINX + PHP-FPM · take cards

unzip → live on a VPS — one afternoon.

Most SaaS dies of complexity, not competition.
Indie builders like Pieter Levels (@levelsio) run profitable products on exactly this shape — PHP · SQLite · jQuery · a cheap VPS per project.
0 SQLite reads / sec
daily_hits100,000+
cost / 10k logins$1
whole_stack / month< $10
reads_block_writesnever · WAL mode
Pricing you control

Tiers, access levels and credits from one config file.

Define plans in app/subscriptions.php, attach Stripe price IDs, and the checkout flow stays generic across every project.

Included

Free

$0

Default access for new users and trial accounts.

Access 025 credits/mo
Subscription

Starter

$19/mo

For a small paid SaaS tier.

Access 10100 credits/mo
Subscription

Pro

$49/mo

For heavier usage and premium features.

Access 20500 credits/mo
Subscription

Scale

$149/mo

For power users and high-credit products.

Access 302,000 credits/mo
Questions

The honest FAQ.

With bearer API keys they generate from their dashboard. Keys are hashed and peppered at rest, can be revoked or rotated, and are capped per user.

Per-key rate limits are built in, and each call can cost credits — so you bill by usage and protect your endpoints from one config.

Yes — plans set access levels and credit grants, so higher tiers get higher limits and more included calls.

Yes — parameterised SQL throughout, signed Stripe webhooks, CSRF, rate limiting and session hardening, all security-reviewed. Real plumbing, not a toy.

One small VPS runs the whole stack for a few dollars a month, and passwordless login emails on Amazon SES are about $1 per 10,000 sign-ins. Prefer Apple or Google sign-in? Both are built in and cost nothing to run — each just needs that provider's active developer account — so you can skip login emails entirely. No per-seat platform bills.

Get started

Ship your SaaS this week.

Passwordless sign-in, Stripe billing, credits and admin — already wired. Copy a folder, rename it, start charging.

Get Access