# `/api/content-studio` — the agent-ready contract The endpoint Kev's `/studio` page reads today and an autonomous poster reads later. **The page is a thin client**: no posting logic, no fact handling. Wiring a bot means pointing it here — nothing on this side changes. Distinct from `/api/content` (Session 29), which serves structured content *objects* by data level. This serves finished **posts**. ## Auth `x-internal-key: $VYNDR_INTERNAL_KEY` — private, never public. The browser never holds the key; the Next proxy at `web/src/app/api/content-studio/[...path]` attaches it server-side. ## `GET /api/content-studio/:date?` `:date` optional, defaults to today ET. ```jsonc { "date": "2026-08-07", "count": 3, "posts": [{ "id": "honesty_flex", "label": "The Honesty Flex", "sport": "mlb", "status": "pending", // pending | approved | skipped | regenerate_requested "ok": true, "skipped": false, "reason": null, // why it was skipped, when it was "honest_absence": false, // a real "nothing tonight" post, not a failure "copy": "WE GRADED 2140 PROPS TONIGHT...", "card": { "title": "...", "lines": [...] }, "card_svg": "", // ready to render or rasterise "fact_contract": ["graded", "ceiling_letter", "..."], // REQUIRED fields "facts": { "graded": 2140, "...": "..." } // what backed it }] } ``` **`fact_contract` + `facts` are the point.** An agent (or a reviewer) can check what a claim rests on instead of trusting the sentence. A post whose contract could not be met never appears with invented values — it arrives `skipped` with a `reason`, or as an `honest_absence`. ## `POST /api/content-studio/:date/:id/status` ```jsonc { "status": "approved" } // approved | skipped | regenerate_requested ``` Editorial state only, stored in Redis for 14 days. **Approving a post changes nothing about the model** — status never touches a serving, model or ledger table. ## For the agent build 1. `GET` the date → filter `ok && !skipped`. 2. Post `copy`; rasterise or attach `card_svg`. 3. `POST` status `approved` on success. 4. **Never** synthesise a claim not present in `facts`. The engine refuses to render an unbacked token; an agent must not reintroduce one downstream. Adding a template changes the payload not at all — a new `id` simply appears.