Project One — API Documentation
Programmatic reference for everything the platform exposes over HTTP: 38 endpoints across 11 resource groups — the console surface (/api/*) plus the versioned programmatic surface (/api/v1/*) — and the conventions they share. Written for three audiences at once: engineers integrating against the platform, AI agents driving it, and us, six months from now.
Integrating a machine? Start with platform-api-v1.md — the /api/v1 surface exists precisely for you (RFC 9457 errors, stable codes, credential-derived tenancy). The legacy /api/* routes serve the console UI.
Start here
- conventions.md — read this first. Demo vs live modes, the three auth tiers, rate limits, body limits, error envelopes, the approval gate, telemetry, and the complete environment-variable list. Every resource page assumes you know it.
- openapi.yaml — the machine-readable spec (OpenAPI 3.1). Feed it to codegen, Postman/Bruno, validators, or an LLM.
- llms.txt — the compact entry point for AI agents.
Resource map
| Page | Endpoints | What lives there |
|---|---|---|
| leads-and-marketing.md | POST /api/leads · POST /api/interest · GET/POST /api/unsubscribe |
Lead capture, tour-gate interest, CAN-SPAM/RFC 8058 unsubscribe |
| bookings.md | GET/POST/OPTIONS /api/bookings · GET/POST /api/bookings/manage · POST /api/bookings/mark |
Slot sets, race-safe booking, the lead's manage link, host-marked outcomes |
| conductor-chat.md | POST /api/conductor |
The member chat bar (live LLM or demo responder, jargon-guarded) |
| approvals.md | POST /api/approvals |
The launch-gate decision endpoint (one-time capability tokens) |
| media.md | POST /api/media (3 actions) · GET /api/vsl |
Photo library, VSL ticket→PUT→confirm, the stable VSL redirect |
| creatives-and-videos.md | POST /api/creatives · POST /api/videos |
Creative decisions and the animate-this-ad video seeding flow |
| video-generation-provider.md | (no HTTP endpoint — backend integration) | The Gemini/Veo ("Nano Banana") video provider: external API contract, config, async lifecycle |
| onboarding-and-brand.md | POST /api/onboarding · POST /api/brand-assets |
Tenant provisioning and brand intake |
| auth.md | POST /api/auth/login · POST /api/auth/logout · GET /auth/confirm |
Sign-in/out and the magic-link landing (redirect surfaces) |
| public-pages.md | GET /p/{instanceId} · GET /p/{instanceId}/thanks |
Served funnel pages |
| internal-cron.md | POST /api/cron |
The scheduled tick (secret-gated) |
| platform-api-v1.md | GET /api/v1/status · /approvals · /creatives · /videos · /performance · /positioning · /angles · /scripts · /landing-page · /brand · POST /api/v1/approvals/{id}/decision · /creatives/{id}/decision · /creatives/{id}/animate · /approvals/pause-request · /approvals/budget-request · PATCH /api/v1/angles/{id} |
The programmatic surface: problem+json errors, demo-labeled reads, fail-closed mutations |
Five things to know before your first call
- Demo vs live is per-response, not per-deployment. Check every success for
"mode": "demo"— it means nothing was persisted. See conventions §2. - Send
Content-Length. Body-guarded routes reject chunked requests with 411 before reading anything. - Everything fails closed now. A configured live failure is an honest 500 on every route —
"mode": "demo"means exactly one thing: the platform is keyless (API slice 0 ended the old fail-open-to-demo-ack behavior). Decisions additionally fail closed on input (exact lowercase"approve"/"reject"). - Real-world actions go through the approval gate. You never trigger a publish/launch directly — you decide a pending approval, and a server-side one-time token executes it. conventions §7.
- Some surfaces aren't JSON. Auth is 303 redirects; unsubscribe and booking-manage are HTML pages; cron errors are plain text. Each page flags its own shape.
How to keep these docs alive (the update contract)
The module is deliberately boring to update:
- One resource group per file under
resources/. Adding an endpoint to an existing group = edit that one file + add the path toopenapi.yaml+ one line in the table above. A brand-new group = new file following the shared template (summary paragraph → endpoint table → per-endpoint Request/Responses/Side effects/Notes →> Source:footer). - Conventions changes go in
conventions.mdonly — resource pages link, never restate. If you're copy-pasting a rate-limit table into a resource page, stop. - Every page ends with
> Source:file paths. When code and doc disagree, the code wins; fix the doc in the same PR as the behavior change. Treat a route diff without a docs diff as a review smell. - The OpenAPI spec is part of the definition of done for any endpoint change — it's what AI tooling and codegen consume, so it drifts loudest.
- Keep the honesty notes (the "Notes for callers" gotchas). They document real behavior — silent drops, anti-enumeration 404s, demo fallbacks — and they're the part future-us will thank present-us for.
Docs generated 2026-07-22 from a source-grounded extraction of every route file; each fact traced to code. Suite state at generation: 319 tests passing.