{"openapi":"3.1.0","info":{"title":"Signal API","version":"0.1.0"},"paths":{"/auth/me":{"get":{"tags":["auth"],"summary":"Me","description":"Identity + onboarding + plan state. One round-trip on first paint\nof any authed page; cached client-side until sign-out.","operationId":"me_auth_me_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["auth"],"summary":"Delete Account","description":"Hard-delete the user's account end-to-end.\n\nOrder of operations:\n  1. Best-effort cancel any active Stripe subscription (logged,\n     non-fatal — a dangling sub is reconcilable; a half-deleted\n     account is not).\n  2. Delete every row the user owns, children-before-parents, in a\n     single transaction. FK CASCADE is inconsistent across child\n     tables (credits/api_keys/modules/oauth cascade; sessions,\n     outputs, brand_*, etc. do NOT) so we delete explicitly. Session-\n     keyed children (outputs, story_picks, scheduled_posts) go before\n     their parent sessions. On any DB error we roll back — the user\n     keeps a working account rather than a half-deleted one.\n  3. Delete the app User row (cascading children clean up here).\n  4. Delete the Supabase auth user via the admin API. Best-effort:\n     the app data is already gone, so a failure here leaves an\n     orphaned auth identity that we log for manual cleanup but still\n     return success.\n\n`users.id` equals the Supabase auth uid — CurrentUser.id comes\nstraight from the Supabase token `id` claim (see app/auth.py\n`_verify_supabase_bearer_token`), and `_ensure_user` writes the row\nwith that same id. So the same UUID drives both the app deletes and\nthe Supabase admin delete.","operationId":"delete_account_auth_me_delete","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/export":{"get":{"tags":["auth"],"summary":"Export My Data","description":"GDPR-style \"download my data\" export.\n\nReturns everything we hold for the authenticated user as a single\nJSON document, served as a file attachment. Deliberately excludes\nsecrets: social-connection OAuth tokens (access_token_enc /\nrefresh_token_enc) and PAT secrets (key_hash) are NEVER included —\nonly display-safe metadata. Giant raw signal blobs on sessions\n(raw_signals / stories / search_plan / niche_profile) are omitted;\nthe user gets their decisions (story/angle picks + headline) and\ntheir finished content (outputs).","operationId":"export_my_data_auth_me_export_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/welcome":{"patch":{"tags":["auth"],"summary":"Mark Welcome Seen","description":"Mark the welcome deck as seen. Called when the user clicks\n'Type your beat →' on the final slide OR clicks 'Skip'. Idempotent —\nre-marking just leaves the existing timestamp in place.","operationId":"mark_welcome_seen_auth_me_welcome_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/profile":{"patch":{"tags":["auth"],"summary":"Update Profile","description":"Set the optional display name shown in the header in place of the email.\nTrimmed + length-capped; empty clears it (back to the email).","operationId":"update_profile_auth_me_profile_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/notifications":{"patch":{"tags":["auth"],"summary":"Update Notification Prefs","description":"Update notification preferences. Only fields present in the body\nare written; omitted fields are left untouched. Returns the updated\nthree booleans.","operationId":"update_notification_prefs_auth_me_notifications_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotificationPrefs"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/security-events":{"get":{"tags":["auth"],"summary":"List Security Events","description":"The user's ~50 most recent account-security events, newest-first.\n\nSurfaces the audit log on /settings (PAT mint/revoke, social\nconnect/disconnect, etc.). `ip` and `user_agent` are deliberately\nNOT returned — they're server-side-only forensic fields.","operationId":"list_security_events_auth_me_security_events_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Security Events Auth Me Security Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/sign-in-event":{"post":{"tags":["auth"],"summary":"Record Sign In","description":"Record a sign-in for the security activity log.\n\nSign-in happens at Supabase, not here, so the web client pings this\non a genuine SIGNED_IN auth event. Supabase fires SIGNED_IN on more\nthan just a fresh login (e.g. tab refocus / token refresh paths), so\nwe dedupe server-side: if a sign_in event for this user already\nlanded in the last 10 minutes, this is a no-op. The IP + user-agent\nare captured here, server-side, where they're trustworthy.","operationId":"record_sign_in_auth_me_sign_in_event_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/email":{"post":{"tags":["auth"],"summary":"Change Email","description":"Start an email change. We hand the new address to Supabase with\n`email_confirm: false` so Supabase fires its re-verification flow —\nwe never auto-confirm.\n\nThe app `users.email` column reconciles on the next token\nverification: `_ensure_user` in app/auth.py rewrites the app row's\nemail whenever the verified Supabase token's email differs (the\n`elif user.email != email` branch). So once the user confirms via the\nlink and their next token carries the new email, the app row follows\nautomatically — no extra sync needed here.","operationId":"change_email_auth_me_email_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChangeEmailRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/sessions/revoke":{"post":{"tags":["auth"],"summary":"Revoke All Sessions","description":"Sign out everywhere — revoke all refresh tokens via the Supabase\nadmin logout endpoint. Existing access tokens keep working until they\nexpire (short TTL), but no new ones can be minted.","operationId":"revoke_all_sessions_auth_me_sessions_revoke_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/api-keys":{"get":{"tags":["auth"],"summary":"List Api Keys","description":"List all keys for the current user, including 24h credit burn\nper PAT. The full token is never returned — only the prefix +\nmetadata + burn.\n\nBurn computation: one GROUP BY on credit_transactions for the\nuser's keys. Avoids N+1; cheap even at hundreds of PATs.","operationId":"list_api_keys_auth_me_api_keys_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Api Keys Auth Me Api Keys Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["auth"],"summary":"Create Api Key Route","description":"Mint a new PAT. The plaintext is returned exactly once in the\nresponse body — the UI must show it immediately and warn the user\nthey won't see it again.\n\nPAT issuance is plan-gated (the locked pricing makes the agent surface\na paid feature): Creator/free = 0, Studio = 1, Operator = unlimited.\nWe gate minting, not per-call — the token IS the capability. Existing\nkeys on a now-ineligible plan are left intact (no retroactive\nlockout); only NEW issuance is blocked.","operationId":"create_api_key_route_auth_me_api_keys_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateKeyResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/auth/me/api-keys/{key_id}":{"delete":{"tags":["auth"],"summary":"Revoke Api Key Route","description":"Soft-delete the key. Subsequent requests with that token return 401.","operationId":"revoke_api_key_route_auth_me_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Key Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions":{"get":{"tags":["sessions"],"summary":"List Sessions","description":"List all sessions for the current user, newest first.","operationId":"list_sessions_sessions_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SessionResponse"},"title":"Response List Sessions Sessions Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["sessions"],"summary":"Start Session","operationId":"start_session_sessions_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartSessionRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/stream":{"get":{"tags":["sessions"],"summary":"Stream Session","description":"SSE endpoint. Client connects and receives progress events until complete.\n\nBrowser `EventSource` cannot attach an Authorization header — so this\nendpoint accepts the Supabase access token via `?token=` query param as a\nfallback. The Bearer-header path still works for non-EventSource callers\n(curl, agent SDKs). Token is shipped over TLS only and never logged.","operationId":"stream_session_sessions__session_id__stream_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/story":{"post":{"tags":["sessions"],"summary":"Select Story","operationId":"select_story_sessions__session_id__story_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"expected_intent_version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expected Intent Version"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StorySelectionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/seen-titles":{"get":{"tags":["sessions"],"summary":"Seen Story Titles","description":"Return the set of normalized titles this user has already picked. Used by\nthe StoryGrid frontend to show the 'Previously covered' badge across runs.","operationId":"seen_story_titles_sessions_seen_titles_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Response Seen Story Titles Sessions Seen Titles Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/stories/refine":{"post":{"tags":["sessions"],"summary":"Refine Stories","operationId":"refine_stories_sessions__session_id__stories_refine_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryRefineRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryWorkspaceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/angle":{"post":{"tags":["sessions"],"summary":"Select Angle","operationId":"select_angle_sessions__session_id__angle_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"expected_intent_version","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expected Intent Version"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AngleSelectionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/thread":{"post":{"tags":["sessions"],"summary":"Resolve Session Thread","description":"Resolve (and, for an orphan, adopt) the thread this run belongs to. The\nsingle redirect target for every legacy entry point (/run, dashboard rows,\nwatched-scan links): they POST here, then route to /chat/{thread_id}. POST\nbecause the first call mutates (adopts the orphan).","operationId":"resolve_session_thread_sessions__session_id__thread_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/retry":{"post":{"tags":["sessions"],"summary":"Retry Session","description":"Resume a FAILED run from its last good checkpoint (the locked angle) —\nre-runs content generation onward without re-scanning. Mints a fresh\nreservation for the remaining work (the failed run's was refunded).","operationId":"retry_session_sessions__session_id__retry_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/angles/regenerate":{"post":{"tags":["sessions"],"summary":"Regenerate Angles","operationId":"regenerate_angles_sessions__session_id__angles_regenerate_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AngleRegenerateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/iron":{"patch":{"tags":["sessions"],"summary":"Edit Iron","description":"Edit the BRIEF (forge-on-order ph.3, edit-once-propagate): reshape the\nhook/frame/tension/CTA or add free-form direction. Every product created\nafter the edit inherits it; products that already exist are marked stale\n(script.brief_changed) and the sheet offers a free re-create. Allowed once\nthe angle is locked (the brief exists) — awaiting_forge, cp3, or complete.","operationId":"edit_iron_sessions__session_id__iron_patch","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IronEditsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/revert-to-story":{"post":{"tags":["sessions"],"summary":"Revert To Story","description":"Go back to CP1 (story selection) from anywhere in or past the pipeline.\nCancels the current orchestrator task, clears all state from CP1 onward,\nand re-spawns. The orchestrator's idempotent stages will skip work that's\nalready done (research, clustering, ranking) and land cleanly at CP1.\n\nAllowed at any point after stories have been ranked — including during\nin-flight stages like generating_angles, applying_voice, generating_content,\nor rendering. The orchestrator handles the cancellation cleanly via\ntask_registry.cancel.","operationId":"revert_to_story_sessions__session_id__revert_to_story_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StoryWorkspaceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/revert-to-angle":{"post":{"tags":["sessions"],"summary":"Revert To Angle","description":"Go back to CP2 (angle selection) from anywhere past angle generation.\nKeeps the selected story; clears the chosen angle and downstream content/renders.\n\nAllowed at any point after angles have been generated — including during\nin-flight stages like applying_voice, generating_content, or rendering.","operationId":"revert_to_angle_sessions__session_id__revert_to_angle_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AngleListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/review":{"post":{"tags":["sessions"],"summary":"Submit Review","operationId":"submit_review_sessions__session_id__review_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReviewSubmitRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/render/image-card":{"post":{"tags":["sessions"],"summary":"Render Image Card Endpoint","description":"On-demand image-card render at CP3. Thin REST wrapper over\napp.services.render — same code path serves the MCP\n`niche_render_image_card` tool.","operationId":"render_image_card_endpoint_sessions__session_id__render_image_card_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ImageCardRenderRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/file":{"post":{"tags":["sessions"],"summary":"File Session Endpoint","description":"Mark a run FILED — the user closed it out (e.g. downloaded all assets).\nSame 'done with it' semantics as publishing; moves the run from open → filed.\nIdempotent: re-filing keeps the original filed_at.","operationId":"file_session_endpoint_sessions__session_id__file_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/retext-card":{"post":{"tags":["sessions"],"summary":"Retext Card Endpoint","description":"FREE re-text / re-color of an existing image card (Pillow re-composite over\nthe retained background — no image gen, no credit). Sets the exact HEADER words\nand optional text color.","operationId":"retext_card_endpoint_sessions__session_id__retext_card_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/RetextCardRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/restore-image":{"post":{"tags":["sessions"],"summary":"Restore Image Endpoint","description":"UNDO: restore the prior image on an output (free, instant). Powers the\nfiling-sheet undo after a header swap dropped a generated image to a card.","operationId":"restore_image_endpoint_sessions__session_id__restore_image_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"cell","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/rerender-slide":{"post":{"tags":["sessions"],"summary":"Rerender Slide Endpoint","description":"Part G: re-render ONE carousel body slide (`slide` = 0-based index into\nslides[]) in place after its text was edited — replaces only static_urls[slide+1]\n(the cover sits at 0), leaving the other slide images byte-identical. The PDF +\ncontact-sheet rebuild live from static_urls. `cell` defaults to linkedin:carousel.","operationId":"rerender_slide_endpoint_sessions__session_id__rerender_slide_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"slide","in":"query","required":true,"schema":{"type":"integer","title":"Slide"}},{"name":"cell","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/card-headline":{"post":{"tags":["sessions"],"summary":"Card Headline Endpoint","description":"Compress a hand-typed hook to its ≤60-char card-headline twin. Cheap +\nfast (the desk precomputes twins for palette variants; this covers custom\nhooks). Returns the short form for the caller to feed into a card re-render.","operationId":"card_headline_endpoint_sessions__session_id__card_headline_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardHeadlineRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/render/twitter-card":{"post":{"tags":["sessions"],"summary":"Render Twitter Card Endpoint","description":"Re-render the X/Twitter preview card with user-supplied words at CP3.\n\nPure local Playwright screenshot — no image-gen vendor call, so this\nis FREE (no credit charge). Edits the words baked into the image, not\nthe posted tweet caption.","operationId":"render_twitter_card_endpoint_sessions__session_id__render_twitter_card_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TwitterCardRenderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/render/video":{"post":{"tags":["sessions"],"summary":"Render Video Endpoint","description":"On-demand reel render at CP3. Thin REST wrapper over\napp.services.render — same code path serves the MCP\n`niche_render_reel` tool.","operationId":"render_video_endpoint_sessions__session_id__render_video_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VideoRenderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/outputs/add":{"post":{"tags":["sessions"],"summary":"Add Output Endpoint","description":"Add an output cell to a session that's at CP3+. Web-facing wrapper\nover the same logic as the niche_add_output MCP tool. Idempotent on\n(session_id, cell) — returns 200 with the existing Output when the\ncell is already on the session.\n\nUsed by the filing sheet's \"+ Add output\" picker to drop in another\nsurface mid-review (e.g. session started with linkedin:text_post,\nuser reviews drafts, decides to also add instagram:carousel).","operationId":"add_output_endpoint_sessions__session_id__outputs_add_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddOutputRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/niches":{"get":{"tags":["sessions"],"summary":"List Niches","description":"Return all distinct niches with run counts and last-run date.","operationId":"list_niches_sessions_niches_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["sessions"],"summary":"Delete Niche","description":"Delete all sessions for a given niche — A7: route EACH through\n`_teardown_session` (cancel + settle-via-release + delete FK children in order),\nnot a raw `sa_delete(Session)`. The raw delete 500'd on any post-CP3 session\n(outputs/story_picks/scheduled_posts FKs have no ON DELETE) and stranded held\ncredits on pre-CP3 ones (`credit_transactions.session_id` SET NULL → the open\nreservation could never be reconstructed/released). Commit per session so one\nbad row doesn't roll back the batch.","operationId":"delete_niche_sessions_niches_delete","parameters":[{"name":"niche","in":"query","required":true,"schema":{"type":"string","title":"Niche"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/niches/rename":{"patch":{"tags":["sessions"],"summary":"Rename Niche","description":"Rename all sessions with old_niche to new_niche.","operationId":"rename_niche_sessions_niches_rename_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NicheRenameRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/niches/merge":{"post":{"tags":["sessions"],"summary":"Merge Niches","description":"Fold all sessions from source niche into target niche, then return combined list.","operationId":"merge_niches_sessions_niches_merge_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NicheMergeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/bulk-delete":{"post":{"tags":["sessions"],"summary":"Bulk Delete Sessions","description":"Delete many owned sessions in one call — the archive's select-all/bulk\ncleanup. Ownership is enforced per id; an id the user doesn't own (or that's\nalready gone) is skipped, not fatal. Commits per session so one bad row\ndoesn't roll back the batch. Returns counts.","operationId":"bulk_delete_sessions_sessions_bulk_delete_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}":{"delete":{"tags":["sessions"],"summary":"Delete Session","description":"Hard-delete a session and everything it owns. Used by the archive UI to\nclean up stalled / failed / abandoned runs. Safe on any owned session\nregardless of status. See _teardown_session for the child-cleanup contract.","operationId":"delete_session_sessions__session_id__delete","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["sessions"],"summary":"Get Session","description":"Returns the session row plus a few derived fields the run page needs\nfor its wait states (niche_profile, selected_story, contributing signals\nfor the picked story).","operationId":"get_session_sessions__session_id__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/provenance":{"get":{"tags":["sessions"],"summary":"Get Provenance","description":"Return the 'how this was made' chain for a completed (or in-review) session.","operationId":"get_provenance_sessions__session_id__provenance_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvenanceResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/module-receipt":{"get":{"tags":["sessions"],"summary":"Get Module Receipt","description":"Per-run module receipt (MODULE_VALUE_VISIBILITY_SPEC §4) — what each paid\nmodule contributed to this run. Empty list when no module sourced anything.","operationId":"get_module_receipt_sessions__session_id__module_receipt_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/module-teasers":{"get":{"tags":["sessions"],"summary":"Get Module Teasers","description":"Locked teasers for modules the user does NOT have (MODULE_VALUE_VISIBILITY_SPEC\n§5) — 'unlock to see them'. Shifts to a resubscribe nudge when the user's trial\nhas lapsed (they once had every module).","operationId":"get_module_teasers_sessions__session_id__module_teasers_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/credits":{"get":{"tags":["sessions"],"summary":"Get Session Credits","description":"Per-run credit breakdown by action. Sums commit-kind rows on the\nledger grouped by `action`. Surfaced on the archive row hover + on\nthe run page's post-run summary card.","operationId":"get_session_credits_sessions__session_id__credits_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditBreakdownResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/sessions/{session_id}/hooks":{"post":{"tags":["sessions"],"summary":"Generate Hook Variants","description":"Generate alternate opening lines for an already-rendered post. Body stays;\nuser picks a hook variant and the frontend replaces the leading paragraph.","operationId":"generate_hook_variants_sessions__session_id__hooks_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookVariantsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HookVariantsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/list":{"get":{"tags":["brand-kit"],"summary":"List Brands","description":"All brand kits the user owns + plan-cap state. Drives the\n/brand-kit roster surface + the composer brand picker.","operationId":"list_brands_brand_kit_list_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/create":{"post":{"tags":["brand-kit"],"summary":"Create Brand","description":"Create a new brand kit. Slug must be unique-per-user + matches\n`[a-z0-9][a-z0-9_-]*`. 402 when the user is at their plan cap;\n409 when the slug is already in use.","operationId":"create_brand_brand_kit_create_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitCreateRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit":{"get":{"tags":["brand-kit"],"summary":"Get Brand Kit","operationId":"get_brand_kit_brand_kit_get","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["brand-kit"],"summary":"Update Brand Kit","operationId":"update_brand_kit_brand_kit_put","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/upload/logo":{"post":{"tags":["brand-kit"],"summary":"Upload Logo","operationId":"upload_logo_brand_kit_upload_logo_post","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_logo_brand_kit_upload_logo_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/upload/wordmark":{"post":{"tags":["brand-kit"],"summary":"Upload Wordmark","operationId":"upload_wordmark_brand_kit_upload_wordmark_post","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_wordmark_brand_kit_upload_wordmark_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/upload/headshot":{"post":{"tags":["brand-kit"],"summary":"Upload Headshot","operationId":"upload_headshot_brand_kit_upload_headshot_post","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_headshot_brand_kit_upload_headshot_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/upload/endcard-image":{"post":{"tags":["brand-kit"],"summary":"Upload Endcard Image","description":"Upload a custom 1080×1920 PNG/JPG to use as the reel endcard.\nWhen set, the renderer short-circuits the Playwright endcard render and\nuses this image as-is (still + Ken-Burns motion via ffmpeg). Replaces\nany previously-uploaded endcard image.","operationId":"upload_endcard_image_brand_kit_upload_endcard_image_post","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_endcard_image_brand_kit_upload_endcard_image_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/upload/endcard-video":{"post":{"tags":["brand-kit"],"summary":"Upload Endcard Video","description":"Upload a custom 1080×1920 MP4 clip (≤ ~5s recommended) to use as the\nreel endcard. The renderer normalizes it (scale-pad to 1080×1920, trim\nor loop to the endcard beat duration, strip audio) and splices it into\nthe reel in place of the rendered endcard PNG.","operationId":"upload_endcard_video_brand_kit_upload_endcard_video_post","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_endcard_video_brand_kit_upload_endcard_video_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/endcard-asset":{"delete":{"tags":["brand-kit"],"summary":"Remove Endcard Asset","description":"Drop the custom endcard image + video so the renderer falls back to\nthe template + mark preference. Doesn't touch the R2 files; orphaned\nbut cheap.","operationId":"remove_endcard_asset_brand_kit_endcard_asset_delete","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/upload/product-image":{"post":{"tags":["brand-kit"],"summary":"Upload Product Image","operationId":"upload_product_image_brand_kit_upload_product_image_post","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_product_image_brand_kit_upload_product_image_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/import/shopify":{"post":{"tags":["brand-kit"],"summary":"Import Shopify","operationId":"import_shopify_brand_kit_import_shopify_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShopifyImportRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/sources":{"delete":{"tags":["brand-kit"],"summary":"Remove Source Asset","description":"Remove a single source asset from the kit's `source_assets` list by URL.\nThe underlying file on R2 is left in place — orphaned, but cheap; a\nsweep job can clean orphans later.","operationId":"remove_source_asset_brand_kit_sources_delete","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","title":"Url"}},{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/reset":{"post":{"tags":["brand-kit"],"summary":"Reset Brand Kit","description":"Wipe the brand kit back to defaults — drops every extracted field,\nevery source asset, every override. Use after removing source files so\nthe kit reflects an empty state instead of stale extractions.\n\nNote: R2 files referenced by old source_assets are left orphan-but-cheap.\nFuture cleanup job sweeps unreferenced keys.","operationId":"reset_brand_kit_brand_kit_reset_post","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/ingest":{"post":{"tags":["brand-kit"],"summary":"Ingest Brand Kit","description":"Drop-zone + URL/text ingest. See `app.services.brand_kit_ingest` for the\nengine. Default fills empty fields + leaves populated ones alone (deepen).\n`replace=True` refreshes an already-populated brand from the new source —\nan explicit \"re-learn this brand\", overwriting detected identity fields.\n\n`scope=visual` (Brand Kit Extractor funnel): a sub-second speed-lane materialize\nthat fills only the color + font fields from a URL (no Playwright/vision, no R2 logo\nupload). Used by the claim-on-login step so a new user lands in the desk already\nbrand-aware. Falls through to the heavy path for any other scope.","operationId":"ingest_brand_kit_brand_kit_ingest_post","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},{"name":"scope","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_ingest_brand_kit_brand_kit_ingest_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IngestReport"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/{brand_id}":{"delete":{"tags":["brand-kit"],"summary":"Delete Brand","description":"Delete a non-default brand kit. Cannot delete the user's default\nbrand — they must promote another first via /set-default.","operationId":"delete_brand_brand_kit__brand_id__delete","parameters":[{"name":"brand_id","in":"path","required":true,"schema":{"type":"string","title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/brand-kit/{brand_id}/set-default":{"post":{"tags":["brand-kit"],"summary":"Set Default Brand","description":"Promote a brand to the user's default. The pipeline picks the\ndefault whenever session_start doesn't pass an explicit brand_id.","operationId":"set_default_brand_brand_kit__brand_id__set_default_post","parameters":[{"name":"brand_id","in":"path","required":true,"schema":{"type":"string","title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/voice/extract":{"post":{"tags":["voice"],"summary":"Extract Voice","description":"Extract voice primitives from 1-10 pasted past posts. Stores on the user's\nVoiceProfile row (creating one if needed). Layers the optional audience + avoid\ndescriptors alongside.\n\nBacked by `app.services.voice_extraction` — the same engine the brand-kit\ningest calls into when it auto-scrapes a social URL.","operationId":"extract_voice_voice_extract_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceExtractRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceExtractResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/voice/questions":{"get":{"tags":["voice"],"summary":"Get Interview Questions","operationId":"get_interview_questions_voice_questions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/voice/interview":{"post":{"tags":["voice"],"summary":"Submit Interview","operationId":"submit_interview_voice_interview_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InterviewRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/voice":{"get":{"tags":["voice"],"summary":"Get Voice Profile","operationId":"get_voice_profile_voice_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VoiceProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/outputs":{"get":{"tags":["outputs"],"summary":"List Outputs","operationId":"list_outputs_outputs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OutputResponse"},"title":"Response List Outputs Outputs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/outputs/{output_id}":{"get":{"tags":["outputs"],"summary":"Get Output","operationId":"get_output_outputs__output_id__get","parameters":[{"name":"output_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Output Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutputResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/outputs/{output_id}/resolve-claim":{"post":{"tags":["outputs"],"summary":"Resolve Claim","description":"Mark a surfaced claim as handled (cut / kept / sourced) so it stops\nbeing surfaced + the publish path stops refusing it. The actual COPY\nedit for cut/keep-generic happens through the normal caption-save path;\nthis records the editorial decision + (for add_source) the citation.","operationId":"resolve_claim_outputs__output_id__resolve_claim_post","parameters":[{"name":"output_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Output Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResolveClaimRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OutputResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/outputs/{output_id}/download":{"get":{"tags":["outputs"],"summary":"Download Output","description":"Download an output as the most natural file for its shape.\n\n  - Pure video (video_url, no images) → returns the MP4 directly.\n  - Single image (image_card with one static_url, no video) → PNG directly.\n  - Everything else → ZIP with images + video + caption.txt.\n\n`part` (Cal 2026-06-05: \"text and an image should be TWO files, not a zip\"):\n  - \"text\"  → just the caption + hashtags as a .txt\n  - \"asset\" → just the image(s)/video, NO caption.txt (single → direct file,\n              multi → zip of assets only)\nThe filing sheet fires part=text + part=asset back-to-back so a text+image\noutput downloads as two clean files instead of one zip.\n\nThe MP4 case is the one Cal flagged 2026-05-25: previously the endpoint\nzipped only static_urls + caption.txt, so a reel download was a tiny zip\nwith a single text file — looked like \"the download is a text file.\"","operationId":"download_output_outputs__output_id__download_get","parameters":[{"name":"output_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Output Id"}},{"name":"part","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Part"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/outputs/session/{session_id}":{"get":{"tags":["outputs"],"summary":"Get Session Outputs","operationId":"get_session_outputs_outputs_session__session_id__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OutputResponse"},"title":"Response Get Session Outputs Outputs Session  Session Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/asset/upload":{"post":{"tags":["asset"],"summary":"Upload Asset","description":"Bring-your-own asset upload — the FAST path for an agent that built a\ngraphic in its own sandbox. The agent curls the raw bytes here over HTTP\n(multipart) instead of re-typing ~63K base64 chars through the model; the\nresponse returns a short-lived, user-bound `upload_ref` to pass to\nniche_attach_image. Stores to the owner-only R2 bucket; the ref maps to it in\nRedis. Validates type/size/decodability up front with named errors.","operationId":"upload_asset_asset_upload_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_asset_asset_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Upload Asset Asset Upload Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/asset/{token}":{"get":{"tags":["asset"],"summary":"Get Asset","operationId":"get_asset_asset__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/connections":{"get":{"tags":["social"],"summary":"List Connections","operationId":"list_connections_social_connections_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ConnectionStatus"},"title":"Response List Connections Social Connections Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/linkedin/connect":{"get":{"tags":["social"],"summary":"Linkedin Connect","operationId":"linkedin_connect_social_linkedin_connect_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/linkedin/callback":{"get":{"tags":["social"],"summary":"Linkedin Callback","operationId":"linkedin_callback_social_linkedin_callback_get","parameters":[{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}},{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"}},{"name":"error","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/instagram/connect":{"get":{"tags":["social"],"summary":"Instagram Connect","operationId":"instagram_connect_social_instagram_connect_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/instagram/callback":{"get":{"tags":["social"],"summary":"Instagram Callback","operationId":"instagram_callback_social_instagram_callback_get","parameters":[{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}},{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"}},{"name":"error","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/twitter/connect":{"get":{"tags":["social"],"summary":"Twitter Connect","operationId":"twitter_connect_social_twitter_connect_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/twitter/callback":{"get":{"tags":["social"],"summary":"Twitter Callback","operationId":"twitter_callback_social_twitter_callback_get","parameters":[{"name":"state","in":"query","required":true,"schema":{"type":"string","title":"State"}},{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"}},{"name":"error","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/{platform}/disconnect":{"delete":{"tags":["social"],"summary":"Disconnect","operationId":"disconnect_social__platform__disconnect_delete","parameters":[{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/{session_id}/{platform}/publish":{"post":{"tags":["social"],"summary":"Publish","operationId":"publish_social__session_id___platform__publish_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/PublishBody"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublishResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/{session_id}/{platform}/schedule":{"post":{"tags":["social"],"summary":"Schedule Post","operationId":"schedule_post_social__session_id___platform__schedule_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Session Id"}},{"name":"platform","in":"path","required":true,"schema":{"type":"string","title":"Platform"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduledPostOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/scheduled":{"get":{"tags":["social"],"summary":"List Scheduled","operationId":"list_scheduled_social_scheduled_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ScheduledPostOut"},"title":"Response List Scheduled Social Scheduled Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/social/scheduled/{scheduled_id}":{"delete":{"tags":["social"],"summary":"Cancel Scheduled","operationId":"cancel_scheduled_social_scheduled__scheduled_id__delete","parameters":[{"name":"scheduled_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Scheduled Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/modules":{"get":{"tags":["modules"],"summary":"Get Modules","description":"Single payload the /modules page reads: full catalog + which the user\nhas, + their plan so the UI can render the Studio bypass state.","operationId":"get_modules_modules_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModulesCatalogResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/modules/{slug}/activate":{"post":{"tags":["modules"],"summary":"Activate Module","description":"Unlock a module for the current user. Free grant today; Stripe checkout\nwill sit in front of this once billing is live (the webhook will call the\nsame `grant_module` underneath so the activation path is single-sourced).","operationId":"activate_module_modules__slug__activate_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleActionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/modules/{slug}/deactivate":{"post":{"tags":["modules"],"summary":"Deactivate Module","description":"Cancel the user's subscription to a module. Row stays around (status\nflipped to `canceled`) so re-activation later preserves the audit trail.\nStudio users can't deactivate per-module — the whole bundle is the SKU.","operationId":"deactivate_module_modules__slug__deactivate_post","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string","title":"Slug"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModuleActionResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/watched":{"get":{"tags":["watched"],"summary":"List Watched","description":"The watched set + the credit-transparency payload.\n\nReadable by any plan so the UI can render the Operator upsell with live\nnumbers; the Operator gate only blocks the mutating routes. Non-Operator\nusers simply get an empty list + cap 0.","operationId":"list_watched_watched_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["watched"],"summary":"Create Watched","description":"Create a watched niche. Operator-gated + cap-enforced.\n\nReturns the refreshed full list payload so the UI re-renders the roster\nand the cost panel in one round-trip.","operationId":"create_watched_watched_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWatchedRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/watched/settings":{"patch":{"tags":["watched"],"summary":"Set Digest Settings","description":"Set the morning-digest delivery hour (UTC). Operator-gated.","operationId":"set_digest_settings_watched_settings_patch","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DigestSettingsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/watched/{watched_id}":{"patch":{"tags":["watched"],"summary":"Update Watched","description":"Edit a watched niche's niche_input / label / brand. Operator-gated.","operationId":"update_watched_watched__watched_id__patch","parameters":[{"name":"watched_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Watched Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWatchedRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["watched"],"summary":"Delete Watched","description":"Delete a watched niche the user owns. Operator-gated.","operationId":"delete_watched_watched__watched_id__delete","parameters":[{"name":"watched_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Watched Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/watched/{watched_id}/pause":{"post":{"tags":["watched"],"summary":"Pause Watched","description":"Pause nightly scanning for one niche. Operator-gated.","operationId":"pause_watched_watched__watched_id__pause_post","parameters":[{"name":"watched_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Watched Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/watched/{watched_id}/resume":{"post":{"tags":["watched"],"summary":"Resume Watched","description":"Resume nightly scanning for one niche. Operator-gated.","operationId":"resume_watched_watched__watched_id__resume_post","parameters":[{"name":"watched_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Watched Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WatchedListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/waitlist":{"post":{"tags":["waitlist"],"summary":"Join Waitlist","operationId":"join_waitlist_waitlist_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WaitlistResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/webhooks/resend":{"post":{"tags":["webhooks"],"summary":"Resend Webhook","operationId":"resend_webhook_webhooks_resend_post","parameters":[{"name":"svix-id","in":"header","required":false,"schema":{"type":"string","default":"","title":"Svix-Id"}},{"name":"svix-timestamp","in":"header","required":false,"schema":{"type":"string","default":"","title":"Svix-Timestamp"}},{"name":"svix-signature","in":"header","required":false,"schema":{"type":"string","default":"","title":"Svix-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/unsubscribe":{"get":{"tags":["unsubscribe"],"summary":"Unsubscribe Get","description":"Footer-link click in a browser → flip the pref + show a confirmation.","operationId":"unsubscribe_get_unsubscribe_get","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["unsubscribe"],"summary":"Unsubscribe Post","description":"RFC 8058 one-click POST (mail client sends `List-Unsubscribe=One-Click`).\nHonor it silently + return 200 regardless so the client shows success.","operationId":"unsubscribe_post_unsubscribe_post","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/portal":{"post":{"tags":["billing"],"summary":"Create Billing Portal","description":"Open the Stripe Billing Portal so the user can manage cards,\nview invoices, cancel subscriptions, or resolve a payment failure.\n\n409 when:\n  - Stripe billing isn't enabled (dev mode w/o Stripe key)\n  - User has no stripe_customer_id yet (hasn't subscribed)","operationId":"create_billing_portal_billing_portal_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingPortalResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/checkout":{"post":{"tags":["billing"],"summary":"Create Checkout","operationId":"create_checkout_billing_checkout_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/checkout/topup":{"post":{"tags":["billing"],"summary":"Create Topup Checkout","description":"One-time credit-pack checkout. Pack is small / medium / large.","operationId":"create_topup_checkout_billing_checkout_topup_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopupRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckoutResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/credits":{"get":{"tags":["billing"],"summary":"Get Credits","description":"Current credit state for /settings/usage — balance, bucket\nexpirations, recent transaction history.\n\nReservation + reservation_release rows are filtered out of the\nuser-facing transaction list. They're internal accounting (hold +\nrelease of unused portion during an in-flight run); the user only\ncares about real debits + grants + refunds. The full ledger is\nstill in the DB, accessible via logs + future admin view. Cal\n2026-05-29: *\"we dont even need to show the reservation at all.\nthats inside baseball as humans say.\"*","operationId":"get_credits_billing_credits_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/auto-topup":{"get":{"tags":["billing"],"summary":"Get Auto Topup","description":"Current auto-top-up state for /settings/usage.","operationId":"get_auto_topup_billing_auto_topup_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoTopupState"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["billing"],"summary":"Update Auto Topup","description":"Enable/disable auto-top-up + tune threshold/pack. Operator-only —\nthe wedge that justifies the tier. Non-Operators get a 403 upgrade\nprompt (the UI hides the control, this is the backstop).","operationId":"update_auto_topup_billing_auto_topup_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoTopupUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutoTopupState"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/billing/webhook":{"post":{"tags":["billing"],"summary":"Stripe Webhook","description":"Stripe webhook handler. Verifies signature, parses event, delegates\nto stripe_billing.handle_event. Returns 200 on every accepted event\n(including no-ops) so Stripe doesn't retry. Returns 400 on signature\nfailure — Stripe surfaces that in the dashboard.","operationId":"stripe_webhook_billing_webhook_post","parameters":[{"name":"Stripe-Signature","in":"header","required":false,"schema":{"type":"string","default":"","title":"Stripe-Signature"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/credits/cap/raise":{"get":{"tags":["credits"],"summary":"Cap Raise","operationId":"cap_raise_credits_cap_raise_get","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/credits/cap/revoke":{"get":{"tags":["credits"],"summary":"Cap Revoke","operationId":"cap_revoke_credits_cap_revoke_get","parameters":[{"name":"token","in":"query","required":false,"schema":{"type":"string","default":"","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp/":{"post":{"tags":["mcp"],"summary":"Mcp Endpoint","description":"Single JSON-RPC 2.0 endpoint. Dispatches on `method`.\n\nAuth model: DISCOVERY is open (initialize / notifications/initialized /\nping / tools/list answer anonymously) so registry health probes (Glama,\nPulseMCP) and browsing agents can introspect the catalog — which is\nalready public via /.well-known/agent-skills/index.json and the Smithery\nlisting, so nothing new is exposed. EXECUTION is gated: every method past\nthe discovery block requires auth (the guard below raises the RFC 9728\nOAuth challenge for anonymous callers), so tools/call + resources/* still\nneed a PAT or OAuth token + credits.","operationId":"mcp_endpoint_mcp__post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/mcp":{"post":{"tags":["mcp"],"summary":"Mcp Endpoint","description":"Single JSON-RPC 2.0 endpoint. Dispatches on `method`.\n\nAuth model: DISCOVERY is open (initialize / notifications/initialized /\nping / tools/list answer anonymously) so registry health probes (Glama,\nPulseMCP) and browsing agents can introspect the catalog — which is\nalready public via /.well-known/agent-skills/index.json and the Smithery\nlisting, so nothing new is exposed. EXECUTION is gated: every method past\nthe discovery block requires auth (the guard below raises the RFC 9728\nOAuth challenge for anonymous callers), so tools/call + resources/* still\nneed a PAT or OAuth token + credits.","operationId":"mcp_endpoint_mcp_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JsonRpcRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/register":{"post":{"tags":["oauth"],"summary":"Register Client","description":"RFC 7591 Dynamic Client Registration. Open endpoint.","operationId":"register_client_oauth_register_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClientRegistrationRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/authorize":{"get":{"tags":["oauth"],"summary":"Authorize","description":"OAuth 2.1 authorize endpoint. Validates the request, then\nredirects to the web-side consent page where the user is auth'd\nvia Supabase + sees the 'Authorize this app?' prompt.","operationId":"authorize_oauth_authorize_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/oauth/authorize/complete":{"post":{"tags":["oauth"],"summary":"Authorize Complete","description":"Internal endpoint — called by the web consent page after the\nuser's decision lands. Mints the auth code on approval, returns the\nredirect URL the web side sends the user to.\n\nAuth: requires a valid Supabase JWT in the Authorization header.\nThe JWT's `sub` claim becomes the authorized user — body cannot\noverride (confused-deputy guard).","operationId":"authorize_complete_oauth_authorize_complete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthorizeCompleteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/oauth/token":{"post":{"tags":["oauth"],"summary":"Token","description":"Exchange an auth code + PKCE code_verifier for an access token.\nThe minted token is a niche_sk_<...> opaque bearer stored in api_keys\nwith oauth_client_id populated.","operationId":"token_oauth_token_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/preview/{token}":{"get":{"tags":["preview"],"summary":"Get Preview","operationId":"get_preview_preview__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Preview Preview  Token  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/threads":{"post":{"tags":["chat"],"summary":"Create Thread","operationId":"create_thread_chat_threads_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateThreadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["chat"],"summary":"List Threads","operationId":"list_threads_chat_threads_get","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/threads/{thread_id}":{"get":{"tags":["chat"],"summary":"Get Thread","operationId":"get_thread_chat_threads__thread_id__get","parameters":[{"name":"thread_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["chat"],"summary":"Patch Thread","operationId":"patch_thread_chat_threads__thread_id__patch","parameters":[{"name":"thread_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PatchThreadRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/threads/{thread_id}/greet":{"post":{"tags":["chat"],"summary":"Greet Thread","description":"Generate the desk's opening line (in voice, personalized) for an empty\nthread. Idempotent-ish: if the thread already has messages, returns the\nfirst one instead of greeting twice.","operationId":"greet_thread_chat_threads__thread_id__greet_post","parameters":[{"name":"thread_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/threads/{thread_id}/messages/stream":{"post":{"tags":["chat"],"summary":"Post Message Stream","description":"The desk's message turn (H-1, now THE message route — the non-streaming\ntwin is gone; the web cut over). Appends the user's turn, runs the desk\ndriver, and streams the reply PROSE token-by-token over SSE (`delta` events),\nthen a terminal `done` event with the persisted messages. The pipeline phase\nfeed (run SSE) is unchanged — it still drives 'what's happening'. [IP] the\nstream carries only assistant prose (run_agent_streaming's text deltas); the\ntool channel never leaves the server.\n\nRecovery contract: the user message is persisted before the driver runs, and\nthe driver turn runs on its OWN db session in a task that survives client\ndisconnect — so a dropped stream is recovered by refetching the thread,\nnever by re-sending (which would run the turn twice).","operationId":"post_message_stream_chat_threads__thread_id__messages_stream_post","parameters":[{"name":"thread_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PostMessageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/threads/{thread_id}/filing-greeting":{"post":{"tags":["chat"],"summary":"Filing Greeting","description":"Fired by the desk the moment a run lands on the filing sheet — Sonnet\n'lights up' with a proactive reaction + next-move offers. Idempotent per\nsession (returns null assistant_message if she already greeted this piece,\nso a reload/double-fire never double-posts).","operationId":"filing_greeting_chat_threads__thread_id__filing_greeting_post","parameters":[{"name":"thread_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/threads/{thread_id}/intelligence-greeting":{"post":{"tags":["chat"],"summary":"Intelligence Greeting","description":"Fired when an intelligence-query run lands at CP1 with a grounded synthesis.\nresearch_query is fire-and-forget, so the persona delivers the actual answer\nhere — narrated from the engine-grounded narratives. Idempotent per session;\nreturns null when the parked run isn't an intelligence query (e.g. a normal\nstart_run also reaches CP1), so the frontend can call it on every CP1 edge.","operationId":"intelligence_greeting_chat_threads__thread_id__intelligence_greeting_post","parameters":[{"name":"thread_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/threads/{thread_id}/slate-greeting":{"post":{"tags":["chat"],"summary":"Slate Greeting","description":"Fired when a NORMAL run parks at a checkpoint — the story slate (CP1) or the\nangles (CP2). The desk narrates whichever just landed with the engine's counsel,\nso the cards don't appear in silence. Idempotent per session+checkpoint (returns\nnull when nothing applies — intel query, not parked, or already greeted), so the\nfrontend can call it on every CP1/CP2 edge.","operationId":"slate_greeting_chat_threads__thread_id__slate_greeting_post","parameters":[{"name":"thread_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Thread Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/preferences":{"get":{"tags":["chat"],"summary":"List Preferences","operationId":"list_preferences_chat_preferences_get","parameters":[{"name":"brand_id","in":"query","required":false,"schema":{"type":"string","default":"default","title":"Brand Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/chat/preferences/{pref_id}":{"delete":{"tags":["chat"],"summary":"Dismiss Preference","operationId":"dismiss_preference_chat_preferences__pref_id__delete","parameters":[{"name":"pref_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Pref Id"}},{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/landing/live-desk":{"get":{"tags":["landing"],"summary":"Landing Live Desk","description":"The newest sanitized snapshot, or an empty feed when none has been produced\nyet. The page falls back to its illustrative DEFAULT_NICHES on an empty feed,\nso this is always safe to call.","operationId":"landing_live_desk_landing_live_desk_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/landing/live-desk/refresh":{"post":{"tags":["landing"],"summary":"Landing Live Desk Refresh","description":"Run the showcase-niche producer + store a fresh snapshot. Token-gated\n(cron-friendly); disabled with 503 when LANDING_REFRESH_TOKEN is unset.","operationId":"landing_live_desk_refresh_landing_live_desk_refresh_post","parameters":[{"name":"x-refresh-token","in":"header","required":false,"schema":{"type":"string","default":"","title":"X-Refresh-Token"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/public/signal-slate":{"get":{"tags":["public"],"summary":"Signal Slate","operationId":"signal_slate_public_signal_slate_get","parameters":[{"name":"niche","in":"query","required":true,"schema":{"type":"string","minLength":2,"maxLength":200,"title":"Niche"}},{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"week","title":"Window"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSlate"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/public/digest-subscribe":{"post":{"tags":["public"],"summary":"Digest Subscribe","description":"Subscribe to the WEEKLY ROLLUP (the Underreported list) — a single, niche-agnostic\neditorial email, NOT a per-niche scan (that's the paid watched-niches feature). Capture-\nonly for now: the email lands in the waitlist table tagged `source='weekly_rollup'` (a\ndistinct, filterable list — keep it OUT of any pre-launch invite blast), and the page it\nconverted on rides a PostHog event as a lead attribute. The rollup SEND + proper list\nmanagement ship with the Underreported Index build.","operationId":"digest_subscribe_public_digest_subscribe_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DigestSubscribeRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/public/seed-from-slate":{"post":{"tags":["public"],"summary":"Seed From Slate","description":"Selection-persistence: the just-signed-up user's free-page pick → a desk thread\nopened on a pre-loaded brief. Reconstitutes the picked story from the (warm) cached\nslate — re-derives if the cache lapsed so the user is never stranded — then seeds a\nparked AWAITING_FORGE session + thread. Returns the thread to open. Flag-gated.","operationId":"seed_from_slate_public_seed_from_slate_post","parameters":[{"name":"authorization","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SeedFromSlateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/public/brand-kit-extract":{"post":{"tags":["public"],"summary":"Brand Kit Extract","operationId":"brand_kit_extract_public_brand_kit_extract_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtractRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BrandKitExtract"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/public/brand-kit-card.png":{"get":{"tags":["public"],"summary":"Brand Kit Card","description":"1200×630 PNG share card for a domain (server-rendered via Pillow, no browser).\nCache-first on the kit (no re-fetch on repeat); the PNG itself is CDN/browser-cached\nvia Cache-Control, and the Pillow composite is ~30ms, so no binary Redis cache needed.","operationId":"brand_kit_card_public_brand_kit_card_png_get","parameters":[{"name":"url","in":"query","required":true,"schema":{"type":"string","minLength":4,"maxLength":2048,"title":"Url"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/.well-known/agent-skills/index.json":{"get":{"tags":["well-known"],"summary":"Agent Skills Manifest","description":"Live agent-skills manifest. Generated from `mcp_tools.TOOLS` on\nevery request so the manifest and `tools/list` can never drift.\n\nShape (loose convention — there isn't a formal standard yet; we use\nfields common to HeyNews, Glama, mcpservers.org listings):\n\n  {\n    \"name\": \"Niche\",\n    \"description\": \"...\",\n    \"category\": \"...\",\n    \"homepage\": \"...\",\n    \"transports\": [\"streamable-http\"],\n    \"endpoint\": \"https://api.nicheangle.com/mcp\",\n    \"auth_methods\": [...],\n    \"skill_count\": 24,  # example only — the live value is len(skills)\n    \"skills\": [{name, description, tags}]\n  }","operationId":"agent_skills_manifest__well_known_agent_skills_index_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/api-catalog":{"get":{"tags":["well-known"],"summary":"Api Catalog","description":"RFC 9727 api-catalog. Linkset JSON pointing at every machine-\nreadable surface we expose: OpenAPI doc, MCP endpoint, agent-skills\nmanifest, docs site. The canonical entry point for API discovery\ncrawlers and tooling that doesn't know about Niche specifically.","operationId":"api_catalog__well_known_api_catalog_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/glama.json":{"get":{"tags":["well-known"],"summary":"Glama Connector Claim","description":"Glama connector ownership claim (glama.ai). Glama fetches this from the\nconnector's domain and verifies the `maintainers` email matches the Glama\naccount email, then marks the listing as claimed. The email is env-driven\n(`GLAMA_MAINTAINER_EMAIL`), never hardcoded — no contact data in the repo,\nand it's a public surface so it should be a COMPANY address. Unset → 404\n(unclaimed).","operationId":"glama_connector_claim__well_known_glama_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-authorization-server":{"get":{"tags":["well-known"],"summary":"Oauth Authorization Server","description":"RFC 8414 — authorization server metadata. Claude Desktop and\nChatGPT app directory clients read this when an MCP server requires\nOAuth, to find the authorize / token / register endpoints + the\nsupported flows.","operationId":"oauth_authorization_server__well_known_oauth_authorization_server_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/oauth-protected-resource":{"get":{"tags":["well-known"],"summary":"Oauth Protected Resource","description":"RFC 9728 — protected resource metadata. Tells the client which\nauthorization servers can issue tokens for this MCP endpoint.","operationId":"oauth_protected_resource__well_known_oauth_protected_resource_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":" Dependency Checks","operationId":"_dependency_checks_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response  Dependency Checks Health Get"}}}}}}},"/health/full":{"get":{"summary":"Health Full","operationId":"health_full_health_full_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/.well-known/mcp.json":{"get":{"summary":"Well Known Mcp","description":"RFC-style discovery doc for the MCP server. Mirrors the OAuth\ndiscovery pattern — agents probe `/.well-known/mcp.json` to find the\nserver URL + auth scheme without needing a pre-known path.\n\nTwo access paths:\n  1. Web tier (nicheangle.com/.well-known/mcp.json) — handled by the\n     Next.js `/api/mcp-discovery` route at web/src/app/api/...\n     Returns `{web_origin}/api/mcp` (Vercel rewrites to Fly internally).\n  2. Direct API (niche-api.fly.dev/.well-known/mcp.json) — this\n     handler. Returns the bare API endpoint `{api_origin}/mcp` (no\n     `/api/` prefix; that's a web-tier rewrite path). The\n     human-facing surfaces (token issue, docs) point at the\n     configured FRONTEND_URL so agents that arrived via the API host\n     still get correct links into the user dashboard.","operationId":"well_known_mcp__well_known_mcp_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AddOutputRequest":{"properties":{"cell":{"type":"string","title":"Cell"},"refresh":{"type":"boolean","title":"Refresh","default":false}},"type":"object","required":["cell"],"title":"AddOutputRequest"},"AngleListResponse":{"properties":{"angles":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Angles"}},"type":"object","required":["angles"],"title":"AngleListResponse"},"AngleRegenerateRequest":{"properties":{"lens":{"type":"string","title":"Lens"},"regen_count":{"type":"integer","title":"Regen Count","default":0}},"type":"object","required":["lens"],"title":"AngleRegenerateRequest"},"AngleSelectionRequest":{"properties":{"angle_id":{"type":"string","title":"Angle Id"}},"type":"object","required":["angle_id"],"title":"AngleSelectionRequest"},"ApiKeyOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"prefix":{"type":"string","title":"Prefix"},"created_at":{"type":"string","title":"Created At"},"last_used_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Used At"},"disabled_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Disabled At"},"burn_24h_credits":{"type":"integer","title":"Burn 24H Credits","default":0}},"type":"object","required":["id","name","prefix","created_at","last_used_at","disabled_at"],"title":"ApiKeyOut"},"AuthorizeCompleteRequest":{"properties":{"client_id":{"type":"string","title":"Client Id"},"redirect_uri":{"type":"string","title":"Redirect Uri"},"scope":{"type":"string","title":"Scope","default":"niche:mcp"},"state":{"type":"string","title":"State","default":""},"code_challenge":{"type":"string","title":"Code Challenge"},"code_challenge_method":{"type":"string","title":"Code Challenge Method","default":"S256"},"approved":{"type":"boolean","title":"Approved"}},"type":"object","required":["client_id","redirect_uri","code_challenge","approved"],"title":"AuthorizeCompleteRequest","description":"Payload posted by the web consent page after the user clicks\nAuthorize / Deny. The authenticated Supabase user (resolved\nserver-side from the Authorization: Bearer header) is the one we\nissue the code for — the body's user_id field is IGNORED if it\ndisagrees with the JWT, to prevent confused-deputy attacks."},"AutoTopupState":{"properties":{"eligible":{"type":"boolean","title":"Eligible"},"enabled":{"type":"boolean","title":"Enabled"},"threshold":{"type":"integer","title":"Threshold"},"pack":{"type":"string","title":"Pack"},"has_card":{"type":"boolean","title":"Has Card"}},"type":"object","required":["eligible","enabled","threshold","pack","has_card"],"title":"AutoTopupState","description":"Operator auto-top-up settings + whether the account can use it."},"AutoTopupUpdate":{"properties":{"enabled":{"type":"boolean","title":"Enabled"},"threshold":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Threshold"},"pack":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pack"}},"type":"object","required":["enabled"],"title":"AutoTopupUpdate"},"BillingPortalResponse":{"properties":{"portal_url":{"type":"string","title":"Portal Url"}},"type":"object","required":["portal_url"],"title":"BillingPortalResponse"},"Body_ingest_brand_kit_brand_kit_ingest_post":{"properties":{"files":{"items":{"type":"string","contentMediaType":"application/octet-stream"},"type":"array","title":"Files"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"},"replace":{"type":"boolean","title":"Replace","default":false}},"type":"object","title":"Body_ingest_brand_kit_brand_kit_ingest_post"},"Body_upload_asset_asset_upload_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_asset_asset_upload_post"},"Body_upload_endcard_image_brand_kit_upload_endcard_image_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_endcard_image_brand_kit_upload_endcard_image_post"},"Body_upload_endcard_video_brand_kit_upload_endcard_video_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_endcard_video_brand_kit_upload_endcard_video_post"},"Body_upload_headshot_brand_kit_upload_headshot_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_headshot_brand_kit_upload_headshot_post"},"Body_upload_logo_brand_kit_upload_logo_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_logo_brand_kit_upload_logo_post"},"Body_upload_product_image_brand_kit_upload_product_image_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_product_image_brand_kit_upload_product_image_post"},"Body_upload_wordmark_brand_kit_upload_wordmark_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_wordmark_brand_kit_upload_wordmark_post"},"BrandKitCreateRequest":{"properties":{"brand_id":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[a-z0-9][a-z0-9_-]*$","title":"Brand Id"},"name":{"type":"string","maxLength":120,"minLength":1,"title":"Name"}},"type":"object","required":["brand_id","name"],"title":"BrandKitCreateRequest"},"BrandKitExtract":{"properties":{"url":{"type":"string","title":"Url"},"domain":{"type":"string","title":"Domain"},"site_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Site Name"},"tagline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tagline"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"palette":{"items":{"$ref":"#/components/schemas/Swatch"},"type":"array","title":"Palette","default":[]},"fonts":{"items":{"$ref":"#/components/schemas/FontInfo"},"type":"array","title":"Fonts","default":[]},"logo":{"anyOf":[{"$ref":"#/components/schemas/LogoInfo"},{"type":"null"}]},"extracted_at":{"type":"string","title":"Extracted At"},"elapsed_ms":{"type":"integer","title":"Elapsed Ms","default":0},"thin":{"type":"boolean","title":"Thin","default":false}},"type":"object","required":["url","domain","extracted_at"],"title":"BrandKitExtract"},"BrandKitListEntry":{"properties":{"brand_id":{"type":"string","title":"Brand Id"},"name":{"type":"string","title":"Name"},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url"},"accent":{"type":"string","title":"Accent"},"is_default":{"type":"boolean","title":"Is Default"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["brand_id","name","accent","is_default","updated_at"],"title":"BrandKitListEntry","description":"Lightweight entry for the brand-roster surface — just the slug,\nname, and a couple of identifying glances so the multi-brand\nswitcher can render without fetching the full BrandKit body for\neach row."},"BrandKitListResponse":{"properties":{"default_brand_id":{"type":"string","title":"Default Brand Id"},"cap":{"type":"integer","title":"Cap"},"can_create_more":{"type":"boolean","title":"Can Create More"},"plan":{"type":"string","title":"Plan"},"brands":{"items":{"$ref":"#/components/schemas/BrandKitListEntry"},"type":"array","title":"Brands"}},"type":"object","required":["default_brand_id","cap","can_create_more","plan","brands"],"title":"BrandKitListResponse"},"BrandKitResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"brand_id":{"type":"string","title":"Brand Id","default":"default"},"name":{"type":"string","title":"Name","default":"Default brand"},"primary_bg":{"type":"string","title":"Primary Bg"},"secondary_bg":{"type":"string","title":"Secondary Bg"},"text_primary":{"type":"string","title":"Text Primary"},"text_secondary":{"type":"string","title":"Text Secondary"},"accent":{"type":"string","title":"Accent"},"headline_font_family":{"type":"string","title":"Headline Font Family"},"body_font_family":{"type":"string","title":"Body Font Family"},"font_size_scale":{"type":"string","title":"Font Size Scale"},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url"},"wordmark_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wordmark Url"},"headshot_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headshot Url"},"product_images":{"items":{},"type":"array","title":"Product Images"},"layout_style":{"type":"string","title":"Layout Style"},"corner_radius":{"type":"integer","title":"Corner Radius"},"tagline":{"type":"string","title":"Tagline"},"boilerplate":{"type":"string","title":"Boilerplate"},"voice_notes":{"type":"string","title":"Voice Notes"},"external_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Url"},"source_assets":{"items":{},"type":"array","title":"Source Assets"},"extraction_status":{"type":"string","title":"Extraction Status"},"forbidden_phrases":{"items":{"type":"string"},"type":"array","title":"Forbidden Phrases"},"signature_phrases":{"items":{"type":"string"},"type":"array","title":"Signature Phrases"},"endcard_mark_preference":{"type":"string","title":"Endcard Mark Preference","default":"auto"},"endcard_outro_text":{"type":"string","title":"Endcard Outro Text","default":""},"endcard_template":{"type":"string","title":"Endcard Template","default":"classic"},"endcard_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endcard Image Url"},"endcard_video_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endcard Video Url"},"video_voice_preference":{"type":"string","title":"Video Voice Preference","default":"auto"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"}},"type":"object","required":["id","primary_bg","secondary_bg","text_primary","text_secondary","accent","headline_font_family","body_font_family","font_size_scale","logo_url","wordmark_url","headshot_url","product_images","layout_style","corner_radius","tagline","boilerplate","voice_notes","external_url","extraction_status","updated_at"],"title":"BrandKitResponse"},"BrandKitUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"primary_bg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Primary Bg"},"secondary_bg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Secondary Bg"},"text_primary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text Primary"},"text_secondary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text Secondary"},"accent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Accent"},"headline_font_family":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headline Font Family"},"headline_font_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headline Font Url"},"body_font_family":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Body Font Family"},"body_font_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Body Font Url"},"font_size_scale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Font Size Scale"},"layout_style":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Layout Style"},"corner_radius":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Corner Radius"},"logo_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Url"},"wordmark_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Wordmark Url"},"headshot_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headshot Url"},"tagline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tagline"},"boilerplate":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Boilerplate"},"voice_notes":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Voice Notes"},"external_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Url"},"cta_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cta Text"},"forbidden_phrases":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Forbidden Phrases"},"signature_phrases":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Signature Phrases"},"endcard_mark_preference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endcard Mark Preference"},"endcard_outro_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endcard Outro Text"},"endcard_template":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endcard Template"},"endcard_image_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endcard Image Url"},"endcard_video_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endcard Video Url"},"video_voice_preference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Voice Preference"}},"type":"object","title":"BrandKitUpdate"},"BulkDeleteRequest":{"properties":{"session_ids":{"items":{"type":"string","format":"uuid"},"type":"array","maxItems":500,"title":"Session Ids"}},"type":"object","title":"BulkDeleteRequest"},"CadencePrimitives":{"properties":{"avg_sentence_words":{"type":"integer","title":"Avg Sentence Words"},"fragment_frequency_pct":{"type":"integer","title":"Fragment Frequency Pct"},"single_para_ratio_pct":{"type":"integer","title":"Single Para Ratio Pct"}},"type":"object","required":["avg_sentence_words","fragment_frequency_pct","single_para_ratio_pct"],"title":"CadencePrimitives"},"CardHeadlineRequest":{"properties":{"hook":{"type":"string","maxLength":600,"minLength":1,"title":"Hook"}},"type":"object","required":["hook"],"title":"CardHeadlineRequest"},"ChangeEmailRequest":{"properties":{"new_email":{"type":"string","format":"email","title":"New Email"}},"type":"object","required":["new_email"],"title":"ChangeEmailRequest"},"CheckoutRequest":{"properties":{"kind":{"type":"string","title":"Kind"},"target":{"type":"string","title":"Target"}},"type":"object","required":["kind","target"],"title":"CheckoutRequest"},"CheckoutResponse":{"properties":{"checkout_url":{"type":"string","title":"Checkout Url"}},"type":"object","required":["checkout_url"],"title":"CheckoutResponse"},"ClientRegistrationRequest":{"properties":{"client_name":{"type":"string","maxLength":200,"minLength":1,"title":"Client Name"},"redirect_uris":{"items":{"type":"string"},"type":"array","title":"Redirect Uris"},"grant_types":{"items":{"type":"string"},"type":"array","title":"Grant Types"},"response_types":{"items":{"type":"string"},"type":"array","title":"Response Types"},"token_endpoint_auth_method":{"type":"string","title":"Token Endpoint Auth Method","default":"client_secret_basic"},"scope":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Scope"},"client_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Uri"},"logo_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Logo Uri"},"tos_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tos Uri"},"policy_uri":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Policy Uri"},"software_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Software Id"},"software_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Software Version"}},"type":"object","required":["client_name"],"title":"ClientRegistrationRequest","description":"Subset of RFC 7591 client metadata we accept. Unknown fields are\nignored (per the spec)."},"ConnectionStatus":{"properties":{"platform":{"type":"string","title":"Platform"},"connected":{"type":"boolean","title":"Connected"},"username":{"type":"string","title":"Username","default":""},"expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Expires At"},"supports_media":{"type":"boolean","title":"Supports Media","default":false},"avatar_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avatar Url"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"verified":{"type":"boolean","title":"Verified","default":false}},"type":"object","required":["platform","connected"],"title":"ConnectionStatus"},"CreateKeyRequest":{"properties":{"name":{"type":"string","title":"Name","default":""}},"type":"object","title":"CreateKeyRequest"},"CreateKeyResponse":{"properties":{"key":{"$ref":"#/components/schemas/ApiKeyOut"},"plaintext":{"type":"string","title":"Plaintext"}},"type":"object","required":["key","plaintext"],"title":"CreateKeyResponse"},"CreateThreadRequest":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Title"},"brand_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"}},"type":"object","title":"CreateThreadRequest"},"CreateWatchedRequest":{"properties":{"niche_input":{"type":"string","maxLength":500,"minLength":1,"title":"Niche Input"},"label":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Label"},"brand_id":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Brand Id"}},"type":"object","required":["niche_input"],"title":"CreateWatchedRequest"},"CreditBreakdownItem":{"properties":{"action":{"type":"string","title":"Action"},"credits":{"type":"integer","title":"Credits"}},"type":"object","required":["action","credits"],"title":"CreditBreakdownItem"},"CreditBreakdownResponse":{"properties":{"session_id":{"type":"string","format":"uuid","title":"Session Id"},"credits_spent":{"type":"integer","title":"Credits Spent"},"items":{"items":{"$ref":"#/components/schemas/CreditBreakdownItem"},"type":"array","title":"Items"},"credits_reserved":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits Reserved"}},"type":"object","required":["session_id","credits_spent","items"],"title":"CreditBreakdownResponse"},"CreditsResponse":{"properties":{"balance":{"type":"integer","title":"Balance"},"ledger_balance":{"type":"integer","title":"Ledger Balance","default":0},"trial_credits_remaining":{"type":"integer","title":"Trial Credits Remaining","default":0},"buckets":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Buckets"},"recent_transactions":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Recent Transactions"}},"type":"object","required":["balance","buckets","recent_transactions"],"title":"CreditsResponse","description":"Current credit state for /billing/credits."},"DigestSettingsRequest":{"properties":{"digest_hour_utc":{"type":"integer","maximum":23.0,"minimum":0.0,"title":"Digest Hour Utc"}},"type":"object","required":["digest_hour_utc"],"title":"DigestSettingsRequest"},"DigestSubscribeRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"niche":{"type":"string","maxLength":120,"title":"Niche","default":""}},"type":"object","required":["email"],"title":"DigestSubscribeRequest"},"ExtractRequest":{"properties":{"url":{"type":"string","maxLength":2048,"minLength":4,"title":"Url"}},"type":"object","required":["url"],"title":"ExtractRequest"},"FontInfo":{"properties":{"name":{"type":"string","title":"Name"},"role":{"type":"string","title":"Role","default":"body"},"is_system":{"type":"boolean","title":"Is System","default":false},"google_font":{"type":"boolean","title":"Google Font","default":false}},"type":"object","required":["name"],"title":"FontInfo"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HookVariantsRequest":{"properties":{"platform":{"type":"string","title":"Platform"},"current_caption":{"type":"string","maxLength":4000,"minLength":1,"title":"Current Caption"},"count":{"type":"integer","title":"Count","default":3}},"type":"object","required":["platform","current_caption"],"title":"HookVariantsRequest"},"HookVariantsResponse":{"properties":{"variants":{"items":{"type":"string"},"type":"array","title":"Variants"}},"type":"object","required":["variants"],"title":"HookVariantsResponse"},"ImageCardRenderRequest":{"properties":{"cell":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell"},"headline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headline"},"style":{"type":"string","title":"Style","default":"photo"},"design_steer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Design Steer"}},"type":"object","title":"ImageCardRenderRequest"},"IngestReport":{"properties":{"kit":{"$ref":"#/components/schemas/BrandKitResponse"},"detected":{"items":{"type":"string"},"type":"array","title":"Detected"},"skipped":{"items":{"type":"string"},"type":"array","title":"Skipped"},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"duration_sec":{"type":"number","title":"Duration Sec","default":0.0}},"type":"object","required":["kit"],"title":"IngestReport","description":"Returned alongside the BrandKit so the UI can show what the engine\ndetected, what it skipped, and what was unchanged."},"InterviewRequest":{"properties":{"archetype":{"type":"string","title":"Archetype"},"answers":{"additionalProperties":{"type":"string"},"type":"object","maxProperties":30,"title":"Answers"},"profile_urls":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":5},{"type":"null"}],"title":"Profile Urls"}},"type":"object","required":["archetype","answers"],"title":"InterviewRequest"},"IronEditsRequest":{"properties":{"hook":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hook"},"frame":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Frame"},"tension":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tension"},"cta_direction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cta Direction"},"notes":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Notes"}},"type":"object","title":"IronEditsRequest","description":"Brief-canvas edits (forge-on-order ph.3). All optional; an explicit \"\"\nclears that edit back to the original. `notes` is free-form direction."},"JsonRpcRequest":{"properties":{"jsonrpc":{"type":"string","title":"Jsonrpc","default":"2.0"},"id":{"anyOf":[{"type":"integer"},{"type":"string"},{"type":"null"}],"title":"Id"},"method":{"type":"string","title":"Method"},"params":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Params"}},"type":"object","required":["method"],"title":"JsonRpcRequest"},"LogoInfo":{"properties":{"kind":{"type":"string","enum":["svg_inline","raster"],"title":"Kind"},"src":{"type":"string","title":"Src"},"fills":{"items":{"type":"string"},"type":"array","title":"Fills","default":[]}},"type":"object","required":["kind","src"],"title":"LogoInfo"},"ModuleActionResponse":{"properties":{"slug":{"type":"string","title":"Slug"},"status":{"type":"string","title":"Status"}},"type":"object","required":["slug","status"],"title":"ModuleActionResponse"},"ModuleBadge":{"properties":{"slug":{"type":"string","title":"Slug"},"label":{"type":"string","title":"Label"},"icon":{"type":"string","title":"Icon"},"sub":{"type":"string","title":"Sub"}},"type":"object","required":["slug","label","icon","sub"],"title":"ModuleBadge","description":"The attribution chip for a story card. A TRUST mark (carries the honest\nconfidence sub-line), not a hype sticker."},"ModuleEntry":{"properties":{"slug":{"type":"string","title":"Slug"},"name":{"type":"string","title":"Name"},"monthly_price_usd":{"type":"integer","title":"Monthly Price Usd"},"state":{"type":"string","title":"State"},"entitled":{"type":"boolean","title":"Entitled"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"checkout_available":{"type":"boolean","title":"Checkout Available"}},"type":"object","required":["slug","name","monthly_price_usd","state","entitled","status","checkout_available"],"title":"ModuleEntry"},"ModulesCatalogResponse":{"properties":{"plan":{"type":"string","title":"Plan"},"studio_includes_all":{"type":"boolean","title":"Studio Includes All"},"stripe_billing_enabled":{"type":"boolean","title":"Stripe Billing Enabled"},"modules":{"items":{"$ref":"#/components/schemas/ModuleEntry"},"type":"array","title":"Modules"}},"type":"object","required":["plan","studio_includes_all","stripe_billing_enabled","modules"],"title":"ModulesCatalogResponse"},"NicheMergeRequest":{"properties":{"source":{"type":"string","title":"Source"},"target":{"type":"string","title":"Target"}},"type":"object","required":["source","target"],"title":"NicheMergeRequest"},"NicheRenameRequest":{"properties":{"old_niche":{"type":"string","title":"Old Niche"},"new_niche":{"type":"string","title":"New Niche"}},"type":"object","required":["old_niche","new_niche"],"title":"NicheRenameRequest"},"NotificationPrefs":{"properties":{"notify_run_complete":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Run Complete"},"notify_trial_marketing":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Trial Marketing"},"notify_product_updates":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Product Updates"},"notify_digest":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Notify Digest"}},"type":"object","title":"NotificationPrefs"},"OutputResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"session_id":{"type":"string","format":"uuid","title":"Session Id"},"platform":{"type":"string","title":"Platform"},"script":{"additionalProperties":true,"type":"object","title":"Script"},"caption":{"type":"string","title":"Caption"},"hashtags":{"items":{"type":"string"},"type":"array","title":"Hashtags"},"static_urls":{"items":{"type":"string"},"type":"array","title":"Static Urls"},"video_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Video Url"},"bundle_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bundle Url"},"published_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Published At"},"published_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Published Url"},"published_platform_post_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Published Platform Post Id"},"scheduled_for":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Scheduled For"},"verifier_blocked_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verifier Blocked Reason"},"verifier_blocked_claim":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verifier Blocked Claim"},"source_faithfulness_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Source Faithfulness Score"},"source_claim_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Claim Count"},"source_ungrounded_claims":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Source Ungrounded Claims"},"surfaced_claims":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Surfaced Claims"},"resolved_claims":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Resolved Claims"},"source_diversity_passed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Source Diversity Passed"},"source_recency_passed":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Source Recency Passed"},"source_distinct_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Distinct Count"},"source_freshest_age_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Source Freshest Age Days"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"density_warnings":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Density Warnings","description":"Per-field over-density (carousel slide / image-card headline / longform\nbody) so the filing sheet flags a too-dense asset instead of silently\nshrink/clipping it (§F). Empty = within caps. Derived, not stored.","readOnly":true},"pdf_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pdf Url","description":"A multi-page PDF of a carousel's slides (LinkedIn document-upload\nfriendly) — one artifact for the whole asset (§G). Carousels only.","readOnly":true},"contact_sheet_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact Sheet Url","description":"A grid PNG of all carousel slides — one image previews the whole asset\n(so an agent/human doesn't assemble it slide-by-slide). Carousels only.","readOnly":true},"asset_expires_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Asset Expires At","description":"When the presigned static/video URLs in THIS response expire (24h from\nserialization) so a consumer knows the TTL instead of guessing (§G).","readOnly":true}},"type":"object","required":["id","session_id","platform","script","caption","hashtags","static_urls","video_url","bundle_url","created_at","density_warnings","pdf_url","contact_sheet_url","asset_expires_at"],"title":"OutputResponse"},"PatchThreadRequest":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Title"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},"type":"object","title":"PatchThreadRequest"},"PostMessageRequest":{"properties":{"content":{"type":"string","maxLength":4000,"minLength":1,"title":"Content"},"turn_id":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Turn Id"}},"type":"object","required":["content"],"title":"PostMessageRequest"},"ProfileUpdate":{"properties":{"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"}},"type":"object","title":"ProfileUpdate"},"ProvenanceResponse":{"properties":{"niche_input":{"type":"string","title":"Niche Input"},"story_title":{"type":"string","title":"Story Title"},"story_summary":{"type":"string","title":"Story Summary"},"angle_frame":{"type":"string","title":"Angle Frame"},"angle_hook":{"type":"string","title":"Angle Hook"},"angle_tension":{"type":"string","title":"Angle Tension"},"angle_cta_direction":{"type":"string","title":"Angle Cta Direction"},"sources":{"items":{"$ref":"#/components/schemas/ProvenanceSource"},"type":"array","title":"Sources"}},"type":"object","required":["niche_input","story_title","story_summary","angle_frame","angle_hook","angle_tension","angle_cta_direction","sources"],"title":"ProvenanceResponse","description":"The 'How this was made' card surfaces the chain: niche → story → angle → sources.\nRenders in CP3 review so users can see (and quote) the reasoning behind their post."},"ProvenanceSource":{"properties":{"title":{"type":"string","title":"Title"},"url":{"type":"string","title":"Url"},"source":{"type":"string","title":"Source"},"publication":{"type":"string","title":"Publication","default":""},"published_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Published At"},"module_badge":{"anyOf":[{"$ref":"#/components/schemas/ModuleBadge"},{"type":"null"}]}},"type":"object","required":["title","url","source"],"title":"ProvenanceSource"},"PublicSlate":{"properties":{"niche":{"type":"string","title":"Niche"},"window":{"type":"string","title":"Window"},"window_label":{"type":"string","title":"Window Label"},"generated_at":{"type":"string","title":"Generated At"},"story_count":{"type":"integer","title":"Story Count"},"stories":{"items":{"$ref":"#/components/schemas/PublicStory"},"type":"array","title":"Stories","default":[]}},"type":"object","required":["niche","window","window_label","generated_at","story_count"],"title":"PublicSlate"},"PublicSource":{"properties":{"title":{"type":"string","title":"Title"},"url":{"type":"string","title":"Url"},"publisher":{"type":"string","title":"Publisher"},"published_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Published At"}},"type":"object","required":["title","url","publisher"],"title":"PublicSource"},"PublicStory":{"properties":{"id":{"type":"string","title":"Id"},"title":{"type":"string","title":"Title"},"headline":{"type":"string","title":"Headline"},"summary":{"type":"string","title":"Summary"},"tags":{"items":{"type":"string"},"type":"array","title":"Tags","default":[]},"engagement":{"type":"string","title":"Engagement","default":"medium"},"sources":{"items":{"$ref":"#/components/schemas/PublicSource"},"type":"array","title":"Sources","default":[]}},"type":"object","required":["id","title","headline","summary"],"title":"PublicStory"},"PublishBody":{"properties":{"override_verifier_block":{"type":"boolean","title":"Override Verifier Block","default":false},"override_acknowledged_claim":{"type":"string","title":"Override Acknowledged Claim","default":""},"acknowledge_publish_cost":{"type":"boolean","title":"Acknowledge Publish Cost","default":false}},"type":"object","title":"PublishBody","description":"Optional publish-time flags. The override pair is the human-only escape\nhatch for a false verifier block — honored only when the acknowledged claim\nmatches the flagged claim verbatim (see dispatch_publish).\n\n`acknowledge_publish_cost` is the human's confirm that a link-bearing X post\nwill cost credits (X bills per link-post). The route returns a 402 with the\ncost the FIRST time; the filing sheet shows it, the human confirms, the\nre-call carries this flag. Mirrors the MCP `acknowledge_publish_cost` gate so\nno surface charges for a link post without an explicit yes."},"PublishResult":{"properties":{"ok":{"type":"boolean","title":"Ok"},"post_url":{"type":"string","title":"Post Url","default":""},"platform_post_id":{"type":"string","title":"Platform Post Id","default":""},"error_kind":{"type":"string","title":"Error Kind","default":""},"error_message":{"type":"string","title":"Error Message","default":""},"retry_after_sec":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Retry After Sec"}},"type":"object","required":["ok"],"title":"PublishResult"},"PunctuationHabits":{"properties":{"em_dashes":{"type":"string","title":"Em Dashes"},"semicolons":{"type":"string","title":"Semicolons"},"parens":{"type":"string","title":"Parens"}},"type":"object","required":["em_dashes","semicolons","parens"],"title":"PunctuationHabits"},"ResolveClaimRequest":{"properties":{"claim":{"type":"string","title":"Claim"},"action":{"type":"string","title":"Action"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"}},"type":"object","required":["claim","action"],"title":"ResolveClaimRequest"},"RetextCardRequest":{"properties":{"cell":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell"},"headline":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Headline"},"subhead":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Subhead"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"}},"type":"object","title":"RetextCardRequest"},"ReviewSubmitRequest":{"properties":{"edits":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Edits"}},"type":"object","required":["edits"],"title":"ReviewSubmitRequest"},"ScheduleRequest":{"properties":{"scheduled_for":{"type":"string","format":"date-time","title":"Scheduled For"}},"type":"object","required":["scheduled_for"],"title":"ScheduleRequest"},"ScheduledPostOut":{"properties":{"id":{"type":"string","title":"Id"},"session_id":{"type":"string","title":"Session Id"},"platform":{"type":"string","title":"Platform"},"scheduled_for":{"type":"string","title":"Scheduled For"},"status":{"type":"string","title":"Status"},"post_url":{"type":"string","title":"Post Url","default":""},"error":{"type":"string","title":"Error","default":""},"created_at":{"type":"string","title":"Created At"},"sent_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sent At"}},"type":"object","required":["id","session_id","platform","scheduled_for","status","created_at"],"title":"ScheduledPostOut"},"SeedFromSlateRequest":{"properties":{"niche":{"type":"string","maxLength":200,"minLength":2,"title":"Niche"},"story_id":{"type":"string","maxLength":80,"title":"Story Id"}},"type":"object","required":["niche","story_id"],"title":"SeedFromSlateRequest"},"SessionResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"status":{"$ref":"#/components/schemas/SessionStatus"},"niche_input":{"type":"string","title":"Niche Input"},"target_platforms":{"items":{"type":"string"},"type":"array","title":"Target Platforms"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"chat_thread_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Chat Thread Id"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"filed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filed At"},"reel_render":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Reel Render"},"iron":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Iron"},"niche_profile":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Niche Profile"},"selected_story":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Selected Story"},"selected_story_signals":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Selected Story Signals","default":[]},"selected_story_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selected Story Id"},"selected_angle_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Selected Angle Id"},"angles":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Angles","default":[]},"ranked_stories":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Ranked Stories","default":[]},"news_peg":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"News Peg"},"recommended_story_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recommended Story Id"},"recommendation_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recommendation Reason"},"pool_thin_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pool Thin Note"},"pool_narrow_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pool Narrow Note"},"credits_spent":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Credits Spent"},"error_message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error Message"},"outcome":{"type":"string","title":"Outcome","description":"Finer ending than raw status (N1): complete / expired / interrupted /\ncancelled / failed / running. Lets the archive show a walk-away (a slate\nWAS produced) distinctly from a real error, instead of a blanket 'Failed'.","readOnly":true}},"type":"object","required":["id","status","niche_input","target_platforms","created_at","updated_at","outcome"],"title":"SessionResponse"},"SessionStatus":{"type":"string","enum":["initializing","expanding_niche","planning_search","discovering_signals","clustering","ranking","cp1_awaiting_story","extracting_signal","generating_angles","cp2_awaiting_angle","applying_voice","generating_content","rendering_static","rendering_video","cp3_awaiting_review","awaiting_forge","complete","failed"],"title":"SessionStatus"},"ShopifyImportRequest":{"properties":{"shop_url":{"type":"string","title":"Shop Url"}},"type":"object","required":["shop_url"],"title":"ShopifyImportRequest"},"StartSessionRequest":{"properties":{"niche_input":{"type":"string","maxLength":500,"minLength":2,"title":"Niche Input"},"target_outputs":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":50},{"type":"null"}],"title":"Target Outputs"},"products_ordered":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Products Ordered"},"target_platforms":{"items":{"type":"string"},"type":"array","maxItems":50,"title":"Target Platforms"},"voice_context":{"anyOf":[{"$ref":"#/components/schemas/VoiceContext"},{"type":"null"}]},"brand_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"},"image_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Kind"}},"type":"object","required":["niche_input"],"title":"StartSessionRequest"},"StoryRefineRequest":{"properties":{"instruction":{"type":"string","maxLength":500,"title":"Instruction"},"dismissed_story_ids":{"items":{"type":"string"},"type":"array","title":"Dismissed Story Ids","default":[]}},"type":"object","required":["instruction"],"title":"StoryRefineRequest"},"StorySelectionRequest":{"properties":{"story_id":{"type":"string","title":"Story Id"}},"type":"object","required":["story_id"],"title":"StorySelectionRequest"},"StoryWorkspaceResponse":{"properties":{"stories":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Stories"},"visible_limit":{"type":"integer","title":"Visible Limit","default":5},"total_candidates":{"type":"integer","title":"Total Candidates"},"has_more_candidates":{"type":"boolean","title":"Has More Candidates"}},"type":"object","required":["stories","total_candidates","has_more_candidates"],"title":"StoryWorkspaceResponse"},"Swatch":{"properties":{"hex":{"type":"string","title":"Hex"},"role":{"type":"string","title":"Role"},"confidence":{"type":"string","enum":["corroborated","declared","supporting","sampled"],"title":"Confidence"},"corroborated":{"type":"boolean","title":"Corroborated","default":false}},"type":"object","required":["hex","role","confidence"],"title":"Swatch"},"TopupRequest":{"properties":{"pack":{"type":"string","title":"Pack"}},"type":"object","required":["pack"],"title":"TopupRequest","description":"Top-up checkout — one-time payment for a credit pack.\npack is one of \"small\" / \"medium\" / \"large\" per docs/PRICING.md."},"TwitterCardRenderRequest":{"properties":{"cell":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell"},"headline":{"type":"string","maxLength":600,"minLength":1,"title":"Headline"},"subhead":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}],"title":"Subhead"}},"type":"object","required":["headline"],"title":"TwitterCardRenderRequest"},"UpdateWatchedRequest":{"properties":{"niche_input":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"title":"Niche Input"},"label":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Label"},"brand_id":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Brand Id"}},"type":"object","title":"UpdateWatchedRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VideoRenderRequest":{"properties":{"captions_enabled":{"type":"boolean","title":"Captions Enabled","default":true},"music_enabled":{"type":"boolean","title":"Music Enabled","default":false},"tone":{"type":"string","title":"Tone","default":"default"},"caption_sync_mode":{"type":"string","enum":["beat","phrase"],"title":"Caption Sync Mode","default":"phrase"},"cell":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cell"}},"type":"object","title":"VideoRenderRequest"},"VoiceContext":{"properties":{"tone_words":{"type":"string","title":"Tone Words","default":""},"audience_context":{"type":"string","title":"Audience Context","default":""},"avoid":{"type":"string","title":"Avoid","default":""}},"type":"object","title":"VoiceContext"},"VoiceExtractRequest":{"properties":{"posts":{"items":{"type":"string"},"type":"array","maxItems":10,"minItems":1,"title":"Posts"},"audience":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"title":"Audience"},"avoid":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"title":"Avoid"}},"type":"object","required":["posts"],"title":"VoiceExtractRequest"},"VoiceExtractResponse":{"properties":{"primitives":{"$ref":"#/components/schemas/VoicePrimitives"},"audience":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience"},"avoid":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Avoid"}},"type":"object","required":["primitives"],"title":"VoiceExtractResponse"},"VoicePrimitives":{"properties":{"insufficient_signal":{"type":"boolean","title":"Insufficient Signal","default":false},"cadence":{"$ref":"#/components/schemas/CadencePrimitives"},"openers":{"items":{"type":"string"},"type":"array","title":"Openers"},"connectors":{"items":{"type":"string"},"type":"array","title":"Connectors"},"taboo_phrases":{"items":{"type":"string"},"type":"array","title":"Taboo Phrases"},"signature_moves":{"items":{"type":"string"},"type":"array","title":"Signature Moves"},"topic_gravity":{"items":{"type":"string"},"type":"array","title":"Topic Gravity"},"casing":{"type":"string","title":"Casing"},"punctuation_habits":{"$ref":"#/components/schemas/PunctuationHabits"}},"type":"object","required":["cadence","openers","connectors","taboo_phrases","signature_moves","topic_gravity","casing","punctuation_habits"],"title":"VoicePrimitives"},"VoiceProfileResponse":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"archetype":{"type":"string","title":"Archetype"},"tone_words":{"items":{"type":"string"},"type":"array","title":"Tone Words"},"stance":{"type":"string","title":"Stance"},"audience_level":{"type":"string","title":"Audience Level"},"hook_style":{"type":"string","title":"Hook Style"},"avoid":{"items":{"type":"string"},"type":"array","title":"Avoid"},"profile_context":{"type":"string","title":"Profile Context"}},"type":"object","required":["id","archetype","tone_words","stance","audience_level","hook_style","avoid","profile_context"],"title":"VoiceProfileResponse"},"WaitlistRequest":{"properties":{"email":{"type":"string","format":"email","title":"Email"},"source":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Source","default":"web"}},"type":"object","required":["email"],"title":"WaitlistRequest"},"WaitlistResponse":{"properties":{"ok":{"type":"boolean","title":"Ok"}},"type":"object","required":["ok"],"title":"WaitlistResponse"},"WatchedListResponse":{"properties":{"plan":{"type":"string","title":"Plan"},"cap":{"type":"integer","title":"Cap"},"can_create_more":{"type":"boolean","title":"Can Create More"},"watched":{"items":{"$ref":"#/components/schemas/WatchedNicheEntry"},"type":"array","title":"Watched"},"estimate_daily_scan_credits":{"type":"integer","title":"Estimate Daily Scan Credits"},"per_scan_credits":{"type":"integer","title":"Per Scan Credits"},"credit_balance":{"type":"integer","title":"Credit Balance"},"balance_floor":{"type":"integer","title":"Balance Floor"},"scan_paused_low_balance":{"type":"boolean","title":"Scan Paused Low Balance"},"digest_hour_utc":{"type":"integer","title":"Digest Hour Utc"}},"type":"object","required":["plan","cap","can_create_more","watched","estimate_daily_scan_credits","per_scan_credits","credit_balance","balance_floor","scan_paused_low_balance","digest_hour_utc"],"title":"WatchedListResponse","description":"The full payload the /watched manager reads in one round-trip.\n\nCarries the watched set plus the credit-transparency numbers so the UI\nnever has to stitch three calls together to render the cost panel."},"WatchedNicheEntry":{"properties":{"id":{"type":"string","title":"Id"},"niche_input":{"type":"string","title":"Niche Input"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"brand_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Brand Id"},"active":{"type":"boolean","title":"Active"},"last_scanned_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Scanned At"},"last_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Session Id"},"created_at":{"type":"string","title":"Created At"}},"type":"object","required":["id","niche_input","label","brand_id","active","last_scanned_at","last_session_id","created_at"],"title":"WatchedNicheEntry"}}}}