All three call POST /v1/assess with TonePerfect-Response: compact, so the app reads the stable compact schema. Start with a test key (tp_test_…): fixed example results, no credits spent. Swap in a live key once the screens work.
Next.js
App: Browser page with MediaRecorder. Key holder: Route handler app/api/assess/route.js.
Files: README.md · package.json · env.example · app/api/assess/route.js · app/page.js · app/layout.js · LICENSE
Expo + Cloudflare Worker
App: React Native app recording M4A with expo-av. Key holder: Cloudflare Worker.
Files: README.md · worker/src/index.js · worker/wrangler.toml · worker/package.json · app/App.js · app/package.json · LICENSE
Flutter + Firebase
App: Flutter app recording AAC with record. Key holder: Firebase HTTPS Function (2nd gen) with an ID-token check.
Files: README.md · pubspec.yaml · lib/main.dart · functions/index.js · functions/package.json · LICENSE
Before you ship
- Put your own sign-in or a per-user limit in front of the proxy. Anyone who finds an open proxy URL can spend your credits.
- Send one
Idempotency-Keyper recording attempt from the app, so a retry after a dropped connection is not charged twice. - Show
error.messageas it comes back; it is written for people. Anassessable: falseresult is not a zero score.
These projects are not published to GitHub or app stores; they are served from this site so you can read every line first. Questions: nik@toneperfect.app.