| Method | Path | Description | Auth |
| POST | /auth/session | Exchange a Google ID token for a 30-day session JWT | Google JWT |
| GET | /me | Current user + per-language profile updated_at + settings updated_at | session JWT |
| DELETE | /me | Wipe the caller's user row (cascades to profiles + settings) — gated by ACCOUNT_DELETE_ALLOWLIST | allowlisted |
| GET | /me/profile/:lang | Server profile for a language (404 if none) | session JWT |
| PUT | /me/profile/:lang | Upsert profile for a language (last-write-wins) | session JWT |
| GET | /me/settings | Server settings (404 if none) | session JWT |
| PUT | /me/settings | Upsert settings (last-write-wins) | session JWT |
| PUT | /me/handle | Claim or release a public handle (3-24 chars, [a-z0-9-]) | session JWT |
| GET | /leaderboard?lang=&limit= | Top opted-in public cards ordered by bestWpm | public |
| GET | /u/:handle | Public card for a claimed handle (404 if none) | public |
| GET | /books | Public Library catalog (slug, title, author, lang, sizes) | public |
| GET | /books/:slug | Full book JSON (paragraphs + chapters) | public |
| GET | /me/books | All of the caller's per-book reading progress | session JWT |
| PUT | /me/books/:slug | Upsert a book's progress (last-write-wins) | session JWT |
| POST | /feedback | Submit a bug report or feature request | optional |
| POST | /tips/checkout | Create a Stripe Checkout Session for a voluntary tip | optional |
| POST | /webhooks/stripe | Stripe webhook receiver (checkout.session.completed) | signature |
| GET | /admin/feedback | List recent feedback rows (newest first) | admin |
| DELETE | /admin/feedback/:id | Delete a feedback row | admin |
| GET | /admin/tips | List recent tips + paid-sum total | admin |