⚠ Superseded snapshot. This page records an earlier plan and may describe choices that were not shipped (e.g. password auth, UUID primary keys, 10-min access + revocable refresh, or an 83-endpoint unified monolith). Current Core reality: magic-link only · 72h identity-only JWT · INT PKs (prod IDs preserved) · a ~13-path Core deployed LIVE at core.oll.am (C0 done) · C2 proven (PR #18). Authoritative now: the live architecture.
oll.am · Consolidated API Contract · Vol. IV

The API Contract

Specview OpenAPI as the base (239 commits, contract-first) + missing endpoints from bubls, intervai, and humanize-me appended. One backend, ~83 endpoints.
~83 endpoints3 conflicts resolvedJune 23, 2026Insights
55
Specview base
+13
Bubls new
+8
Intervai new
+1
Humanize new
~83
Total endpoints
Base

Specview Base — 55 endpoints (copy openapi.yaml verbatim)

MethodPathPurposeAuth
GET/api/healthHealth check
GET/api/health/neonNeon DB connectivity check
GET/api/health/stripeStripe connectivity check
GET/api/health/securitySecurity headers check
POST/api/auth/registerRegister new user
POST/api/auth/loginLogin, returns JWT
GET/api/auth/meGet current userBearer JWT
POST/api/auth/refreshRefresh JWT tokenBearer JWT
GET/api/billing/statusGet subscription statusBearer JWT
POST/api/billing/create-checkout-sessionCreate Stripe checkoutBearer JWT
GET/api/billing/verify-sessionVerify checkout completedBearer JWT
POST/api/billing/webhookStripe webhook receiverStripe-Signature
POST/api/billing/portalCustomer portal sessionBearer JWT
GET/api/projectsList user's projectsBearer JWT
POST/api/projectsCreate projectBearer JWT
GET/api/projects/{id}Get projectBearer JWT
DELETE/api/projects/{id}Delete projectBearer JWT
POST/api/projects/{id}/coherenceCheck spec coherenceBearer JWT
PUT/api/projects/{id}/files/{filename}Save fileBearer JWT
GET/api/projects/{project_id}/files/{filename}/historyFile historyBearer JWT
GET/api/projects/{project_id}/files/{filename}/diffFile diffBearer JWT
POST/api/projects/{project_id}/files/{filename}/revertRevert fileBearer JWT
POST/api/projects/{id}/repairAI repair specBearer JWT
POST/api/projects/{id}/shareShare project (slug)Bearer JWT
POST/api/projects/{id}/claimClaim shared projectBearer JWT
POST/api/projects/{project_id}/generate-taskGenerate taskBearer JWT
GET/api/projects/{project_id}/generate-task/statusTask pollBearer JWT
POST/api/projects/{project_id}/cancelCancel generationBearer JWT
POST/api/projects/{project_id}/regenerate-taskRegen taskBearer JWT
GET/api/context/{key}Get context valueBearer JWT
PUT/api/context/{key}Set context valueBearer JWT
POST/api/ai/text/generate-specGenerate full specBearer JWT
POST/api/ai/text/iterateIterate on sectionBearer JWT
POST/api/ai/text/bootstrap-projectBootstrap project (async)Bearer JWT
GET/api/ai/text/bootstrap-project/status/{job_id}Poll bootstrapBearer JWT
POST/api/ai/text/bootstrap-project/{job_id}/cancelCancel bootstrapBearer JWT
POST/api/ai/text/bootstrap-project/{job_id}/retryRetry bootstrapBearer JWT
POST/api/ai/text/anonymous/bootstrap-projectAnonymous bootstrap
GET/api/ai/text/anonymous/bootstrap-project/status/{job_id}Poll anon bootstrap
GET/api/ai/statsAI usage statsBearer JWT
POST/api/expandExpand textBearer JWT
POST/api/compressCompress textBearer JWT
POST/api/clarifyClarify textBearer JWT
POST/api/simplifySimplify textBearer JWT
POST/api/tldrTL;DR summaryBearer JWT
POST/api/bulletsBullet listBearer JWT
POST/api/brainstormBrainstorm ideasBearer JWT
POST/api/rewriteRewrite text (doc-editing, JSON)Bearer JWT
POST/api/spec-gen/generateSpec generationBearer JWT
GET/api/templates/spec-indexSpec templates indexBearer JWT
GET/api/templates/readmeREADME templateBearer JWT
POST/api/templates/timelineTimeline templateBearer JWT
POST/api/public/analyzePublic braindump analyze
GET/api/public/analyze/{job_id}Poll public analyze
GET/api/public/share/{slug}Get shared spec
Bubls

+ Photoshoot (bubls → Replicate LoRA)

MethodPathPurposeAuth
GET,POST/api/photoshoot/generateGenerate AI headshots via Replicate LoRABearer JWT
GET/api/photoshoot/active-modelGet the active LoRA modelBearer JWT
GET/api/photoshoot/historyPhotoshoot history for userBearer JWT
Bubls

+ Text Operations (bubls streaming humanize + chains)

MethodPathPurposeAuth
POST/api/text/rewrite/streamStream-humanize text (text/plain chunks)Bearer JWT
POST/api/text/chainRun a text transformation chainBearer JWT
POST/api/text/chain/importImport a custom text chainBearer JWT
Bubls

+ User / Track / Waitlist (bubls)

MethodPathPurposeAuth
POST/api/user/onboarding/skipSkip onboardingBearer JWT
PUT/api/user/builderUpdate builder profileBearer JWT
POST/api/user/entitlementsSync payment entitlementsBearer JWT
POST/api/trackTrack analytics eventBearer JWT
GET/api/track/verdictAnalytics verdictBearer JWT
POST/api/waitlist/signupAdd to waitlist
Intervai

+ Interview Sessions (intervai → Tavus CVI)

MethodPathPurposeAuth
POST/api/sessionsCreate interview session (Tavus CVI)Bearer JWT
GET/api/sessions/{session_id}Get sessionBearer JWT
POST/api/sessions/{session_id}/endEnd sessionBearer JWT
POST/api/sessions/{session_id}/reportGenerate AI reportBearer JWT
GET/api/sessions/{session_id}/reportGet reportBearer JWT
POST/api/demo/startStart demo session
POST/api/webhooks/tavusTavus webhook (auto-report)Tavus-Signature
GET/api/configFrontend config / feature flags
Humanize

+ Usage Meter (humanize-me)

MethodPathPurposeAuth
GET/api/usageCurrent user daily usage countBearer JWT
Resolve

Conflicts

/api/rewrite vs /api/text/rewrite/stream

specview has generic doc-editing /api/rewrite (JSON); humanize/bubls need /api/text/rewrite/stream (streaming text/plain). Keep both — different namespace and response type.

resolved

/api/billing/* vs /api/stripe/* vs /api/checkout and /api/portal

intervai uses /api/stripe/checkout + /api/stripe/portal; humanize uses /api/checkout + /api/portal. Normalise all to /api/billing/* (specview spine). One Stripe account, one billing module.

resolved

JWT auth (/api/auth/*) vs Supabase cookies (humanize)

specview JWT is the canonical auth. humanize migrates: supabase.auth.getSession() → Capacitor Preferences storage adapter, pass JWT as Bearer to Flask. Medium effort, required for Capacitor/mobile.

pending
Auth / Billing / Rewrite

3 Decisions — Auth · Billing · Rewrite

1. Auth — specview JWT wins

All products use POST /api/auth/register + POST /api/auth/login (specview spine, HS256 JWT). humanize-me migrates off Supabase cookies: swap createBrowserClientcreateClient with a Capacitor Preferences storage adapter. The Supabase Postgres tables (texts, user_usage) are still queried via a thin Flask passthrough so the shell stays JWT-only.

2. Billing — one /api/billing/* namespace

All checkout/webhook/portal flows normalised to /api/billing/* (specview module). Each product passes a product_key param to the checkout endpoint so one webhook handler routes to the right entitlement. One oll.am Stripe account. Revenue aggregates on TrustMRR automatically.

POST /api/billing/create-checkout-session
Body: { "price_id": "price_...", "product_key": "photoshoot|humanize|spec|interview" }

POST /api/billing/webhook
Header: Stripe-Signature
Body: routes on product_key in metadata

3. Rewrite — two coexisting endpoints

Keep both — they do different things:
POST /api/rewrite — specview doc-editing rewrite, JSON request/response.
POST /api/text/rewrite/stream — bubls/humanize streaming humanizer, returns text/plain chunks (raw concatenated, NOT SSE). Angular reads via fetch + getReader() + TextDecoder.