{"openapi":"3.1.0","info":{"title":"Interviewer","version":"0.1.0"},"paths":{"/v1/admin/stats":{"get":{"tags":["admin"],"summary":"Get Stats","description":"Platform-wide statistics.","operationId":"get_stats_v1_admin_stats_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/activity":{"get":{"tags":["admin"],"summary":"Get Activity","description":"Recent interviews across all orgs.","operationId":"get_activity_v1_admin_activity_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/performance":{"get":{"tags":["admin"],"summary":"Get Performance Analytics","description":"System-wide pause-latency aggregates, grouped by (language, had_image, eou_backend, stt_provider).\n\nPause anchor: `actual_pause_ms` (ground truth, anchored on the user's\nlast-word end, computed post-hoc by `agent/actual_eou.py`) when present;\nfalls back to `pause_ms` (framework-estimated, anchored on the EOU\ndecision moment) when not. The `pct_truth_anchored` column shows what\nfraction of each bucket's turns are on the truth-anchored value vs the\nestimate-anchored fallback — 100% means fully trustworthy comparison.\n\nBucket decomposition (same as the per-conversation UI in\nweb/src/lib/timingBreakdown.ts):\n  recognition = max(eou_delay_ms, transcription_delay_ms)   ← they overlap\n  hook        = on_user_turn_completed_delay_ms\n  llm_ttft    = llm_ttft_ms\n  tts_ttfb    = tts_ttfb_ms\n  residual    = pause_authoritative − (recognition + hook + ttft + ttfb)\n\nAlso returns EOU-effectiveness signals — the only way to evaluate whether\na turn-taking change actually helped without trading pause for cutoffs:\n  avg_estimation_error_ms  — signed avg(eou_estimation_error_ms)\n                             (>0 = waited past real end; <0 = cut off)\n  p5/p95 estimation error  — the distribution shape, since the mean alone\n                             hides cut-offs hiding under late waits\n  cutoff_rate              — fraction of turns flagged\n                             `was_premature_jump_in` by the agent's\n                             post-hoc tagging pass\n\n`eou_estimation_error_ms` and `was_premature_jump_in` come from\n`agent/actual_eou.py`'s ground-truth pass on the settled STT transcript\n(last-word timestamp = true end of speech). Older turns lacking the\npost-hoc pass simply contribute NULLs to the means; cutoff_rate counts\nNULL as not-a-cutoff (conservative).\n\n`eou_backend` is read from `telemetry.eou_effective.backend` (the\nresolved per-session value, respects template overrides — added in PR\n#598). For sessions predating that field, falls back to the system-wide\n`telemetry.audio_config_at_session_start.eou.turn_detector_backend`.\nFinal default is 'text' (the only historical option).\n\nAggregation is on-demand over the existing `sessions.transcript` JSONB +\n`telemetry` — no new tables, no backfill. If the JSONB scan becomes slow\nat scale, materialise into a rollup table; until then this is the\nsimplest correct thing.\n\nSessions without a recorded `telemetry.stt_config.language` are excluded\n(per the plan — they would group under `unknown` which isn't actionable).\n\nParam `days` is \"7\" | \"30\" | \"all\"; default 7.","operationId":"get_performance_analytics_v1_admin_performance_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"string","default":"7","title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eou-preemption-analysis/debug":{"get":{"tags":["admin"],"summary":"Eou Preemption Analysis Debug","description":"Diagnostic for eou-preemption-analysis: row counts at each filter stage.","operationId":"eou_preemption_analysis_debug_v1_admin_eou_preemption_analysis_debug_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":7,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eou-preemption-analysis":{"get":{"tags":["admin"],"summary":"Eou Preemption Analysis","description":"Offline viability check for synthesized PREFLIGHT_TRANSCRIPT.\n\nFor each assistant turn that has `eou_probability_samples` recorded, asks:\nwhen did Smart Turn v3 first cross `threshold`, vs. when did the STT\nfinal transcript arrive? If Smart Turn fires reliably *before* the STT\nfinal, it's a viable trigger for speculative LLM kickoff in languages\nthat don't have Flux's native eager-EOT (Spanish, etc.).\n\nSources considered as \"smart turn\": `smart_turn_v3` and\n`smart_turn_v3_shadow` (the shadow-mode label).\n\nReturned per language:\n  - turns: total turns with any smart-turn samples\n  - crossed_count: turns where Smart Turn ever crossed threshold\n  - crossed_pct: 100 * crossed_count / turns\n  - early_advantage_ms: how many ms Smart Turn's first crossing\n      preceded the STT final (positive = useful; negative = too late).\n      Reported as p10/p50/p90.\n  - false_cross_count: number of times the signal crossed threshold\n      then dropped back below before the final crossing.\n      Reported as mean/p50/p90.\n  - crossing_count_total: total threshold crossings per turn (mean).","operationId":"eou_preemption_analysis_v1_admin_eou_preemption_analysis_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":7,"title":"Days"}},{"name":"threshold","in":"query","required":false,"schema":{"type":"number","maximum":0.99,"minimum":0.1,"default":0.7,"title":"Threshold"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eou-preemption-analysis/sweep":{"get":{"tags":["admin"],"summary":"Eou Preemption Analysis Sweep","description":"Threshold sweep + wiring diagnostic for the synthesized-PREFLIGHT lever.\n\nSeparates two hypotheses for why Smart Turn's first 0.7-crossing fires\nafter is_final:\n  H1 — threshold too high: signal IS rising before is_final, just doesn't\n        hit 0.7 in time. Lower threshold → earlier crossings.\n  H2 — wiring issue: Smart Turn isn't *invoked* until late. Samples\n        physically don't exist before is_final. No threshold change helps.\n\nPer language returns:\n  - first_sample_advantage_ms_*  — when the FIRST Smart Turn sample\n      (any prob) fires relative to is_final. Positive = sample exists\n      before is_final. Negative = no samples until after. This is the\n      H2 diagnostic.\n  - max_prob_before_is_final_*   — across the samples that DID land\n      before is_final, what was the highest probability seen?\n      Tells us whether lowering the threshold could possibly help.\n  - thresholds: per threshold (0.3, 0.4, 0.5, 0.6, 0.7), the crossed_pct\n      and early_advantage_p50. The H1 diagnostic.","operationId":"eou_preemption_analysis_sweep_v1_admin_eou_preemption_analysis_sweep_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"days","in":"query","required":false,"schema":{"type":"integer","maximum":90,"minimum":1,"default":30,"title":"Days"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/active-sessions":{"get":{"tags":["admin"],"summary":"Get Active Sessions","description":"Currently in-progress sessions.","operationId":"get_active_sessions_v1_admin_active_sessions_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/orgs":{"get":{"tags":["admin"],"summary":"List Orgs","description":"List all organizations with counts.","operationId":"list_orgs_v1_admin_orgs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/orgs/{org_id}":{"get":{"tags":["admin"],"summary":"Get Org Detail","description":"Org detail with users, templates, interviews.","operationId":"get_org_detail_v1_admin_orgs__org_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin"],"summary":"Update Org","description":"Update org name/email.","operationId":"update_org_v1_admin_orgs__org_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin"],"summary":"Delete Org","description":"Delete an organization and all its data.","operationId":"delete_org_v1_admin_orgs__org_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/orgs/{org_id}/block":{"post":{"tags":["admin"],"summary":"Block Org","description":"Block an organization from logging in.","operationId":"block_org_v1_admin_orgs__org_id__block_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/orgs/{org_id}/unblock":{"post":{"tags":["admin"],"summary":"Unblock Org","description":"Unblock an organization.","operationId":"unblock_org_v1_admin_orgs__org_id__unblock_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"org_id","in":"path","required":true,"schema":{"type":"string","title":"Org Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users":{"get":{"tags":["admin"],"summary":"List Users","description":"List all users across orgs with their org + authored-template count.\nSearchable by user name/email or org name (q). Mirrors /orgs.","operationId":"list_users_v1_admin_users_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"q","in":"query","required":false,"schema":{"type":"string","default":"","title":"Q"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users/{user_id}":{"get":{"tags":["admin"],"summary":"Get User Detail","description":"User detail: their org + the templates they authored.","operationId":"get_user_detail_v1_admin_users__user_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin"],"summary":"Update User","description":"Change a user's role and/or move them to another org. Moving away or\ndemoting the org's last active owner is blocked. Block via /block.","operationId":"update_user_v1_admin_users__user_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin"],"summary":"Delete User","description":"Hard-delete a user. Authored templates stay in the org but lose\nattribution (created_by -> NULL via the FK ON DELETE rule); use /block\nto preserve it. The org's last active owner can't be deleted.","operationId":"delete_user_v1_admin_users__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users/{user_id}/block":{"post":{"tags":["admin"],"summary":"Block User","description":"Hard-block a user from authenticating anywhere (non-destructive —\npreserves their data + authorship). Distinct from membership status.","operationId":"block_user_v1_admin_users__user_id__block_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/users/{user_id}/unblock":{"post":{"tags":["admin"],"summary":"Unblock User","description":"Restore a blocked user's access.","operationId":"unblock_user_v1_admin_users__user_id__unblock_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/interviews":{"get":{"tags":["admin"],"summary":"List All Interviews","description":"List all interviews across all orgs.","operationId":"list_all_interviews_v1_admin_interviews_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"feedback","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feedback"}},{"name":"reflection_severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reflection Severity"}},{"name":"reflection_tag","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reflection Tag"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/sessions":{"get":{"tags":["admin"],"summary":"List All Sessions","description":"List all sessions across all orgs, joined to their parent interview.\n\nPer-session cardinality variant of `GET /v1/admin/interviews`. Same\nfilter knobs (status filters interview status; feedback/reflection\nsemantics unchanged since reflection lives on the interview row but\nfeedback lives on the session row). Ordering is by session start desc\nso the admin sees today's calls first, even when they're continuations\nof an older interview.","operationId":"list_all_sessions_v1_admin_sessions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}},{"name":"feedback","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Feedback"}},{"name":"reflection_severity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reflection Severity"}},{"name":"reflection_tag","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reflection Tag"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/reflection/tags":{"get":{"tags":["admin"],"summary":"List Reflection Tags","description":"Return distinct reflection tags with usage counts across all interviews.","operationId":"list_reflection_tags_v1_admin_reflection_tags_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/interviews/{interview_id}/reflect":{"post":{"tags":["admin"],"summary":"Rerun Reflection","description":"Re-dispatch the self-reflection pipeline for a single interview (admin only).","operationId":"rerun_reflection_v1_admin_interviews__interview_id__reflect_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"interview_id","in":"path","required":true,"schema":{"type":"string","title":"Interview Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/interviews/{interview_id}/rerun-outputs":{"post":{"tags":["admin"],"summary":"Rerun Outputs","description":"Re-run all configured outputs for an interview (admin only).\n\nMotivating use case: a setup-assistant onboarding webhook crashed mid-\npipeline (e.g. a code bug) and the template was never created. After\ndeploying the fix we want the outputs to retry without forcing the\nuser to redo the conversation. Re-running outputs blindly does that —\nthe setup-assistant webhook fires again and creates the template from\nthe existing transcript + frames.\n\nAll outputs are re-run, including ones that previously succeeded. For\nwebhook outputs this means the receiver may be hit twice. Admins are\nexpected to know this and only invoke this when re-delivery is\nacceptable (or when the prior attempt clearly didn't side-effect, as\nis the case for an HTTP 500 from our own internal webhook handler).\n\nMirrors the dispatcher in /v1/sessions/{id}/result that runs at\nnatural session end — the same _process_interview_background helper,\nsame context-load logic, same persistence.","operationId":"rerun_outputs_v1_admin_interviews__interview_id__rerun_outputs_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"interview_id","in":"path","required":true,"schema":{"type":"string","title":"Interview Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/interviews/{interview_id}/recompute-cost":{"post":{"tags":["admin"],"summary":"Recompute Interview Cost","description":"Re-price every session in this interview using the current rates blob.\n\nMotivating case: the agent stamps `cost_breakdown` onto each session at\nend-of-call using the rates active at that moment. If pricing_rates was\nupdated later (admin PATCH, new models added to the seed), the stored\ntotals are stale — typically $0 for any model that wasn't yet priced.\nThe raw token counts, audio durations, and character counts ARE\npreserved per-turn, so we can recompute cleanly from stored data.\n\nIdempotent. Running twice produces the same result. Does NOT recompute\nthe interview's processing_cost (output generation) — that's a separate\npipeline; we can add a sister endpoint if it becomes a real need.","operationId":"recompute_interview_cost_v1_admin_interviews__interview_id__recompute_cost_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"interview_id","in":"path","required":true,"schema":{"type":"string","title":"Interview Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/sessions/{session_id}/recompute-actual-pause":{"post":{"tags":["admin"],"summary":"Recompute Actual Pause One","description":"Re-run the corrected end-of-speech anchor pass on one session.\n\nUse this to verify the fix on a known-bad session (e.g. f79d15c7) before\nrunning the batch endpoint. Returns the before/after pause for each\nassistant turn so the caller can sanity-check the deltas.","operationId":"recompute_actual_pause_one_v1_admin_sessions__session_id__recompute_actual_pause_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"Preview changes without writing","default":false,"title":"Dry Run"},"description":"Preview changes without writing"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/sessions/{session_id}/timing-debug":{"get":{"tags":["admin"],"summary":"Session Timing Debug","description":"Per-turn forensic dump of pause-relevant timing fields.\n\nReturns a flat list interleaving user segments and assistant timings\nin chronological order, including the exact `last_word_end_at`,\n`segment_started_at`, `agent_speak_at`, and `actual_speech_end_at`\nvalues stored on disk. For investigating pause anchors when the\ndashboard reports a value that doesn't match what a human heard.","operationId":"session_timing_debug_v1_admin_sessions__session_id__timing_debug_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/sessions/{session_id}/debug":{"post":{"tags":["admin"],"summary":"Session Debug Command","description":"Send a debug command to a live agent session via LiveKit data channel.\n\nSupported commands:\n  force_llm_timeout  — makes the agent's LLM appear to hang for N turns,\n                       triggering the LLM watchdog so you can hear the\n                       bridge utterances in production.\n\nBody: {\"command\": \"force_llm_timeout\", \"turns\": 1}","operationId":"session_debug_command_v1_admin_sessions__session_id__debug_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/sessions/recompute-actual-pause":{"post":{"tags":["admin"],"summary":"Recompute Actual Pause All","description":"Batch backfill across every completed session.\n\nStreams sessions in chronological order. Idempotent — sessions already\non the corrected anchor (e.g. ones that ran after deploy and so carry\n`last_word_end_at` on their user segments) get the same numbers back\nout, so no row is rewritten unnecessarily. With `dry_run=true`, walks\nthe data and reports counts without writing.","operationId":"recompute_actual_pause_all_v1_admin_sessions_recompute_actual_pause_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"dry_run","in":"query","required":false,"schema":{"type":"boolean","description":"Count without writing","default":false,"title":"Dry Run"},"description":"Count without writing"},{"name":"limit","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}],"description":"Cap on sessions processed","title":"Limit"},"description":"Cap on sessions processed"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/interviews/{interview_id}":{"delete":{"tags":["admin"],"summary":"Delete Interview","description":"Delete an interview and its sessions/moments.","operationId":"delete_interview_v1_admin_interviews__interview_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"interview_id","in":"path","required":true,"schema":{"type":"string","title":"Interview Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/system-templates":{"get":{"tags":["admin"],"summary":"List System Templates","description":"List system-org templates (admin-only: Setup Assistant, First-Login Onboarding, etc.).\n\nIncludes inheritance metadata so the admin list view can show child rows\nwith a \"↳ variant of [parent]\" subtitle without N+1 round-trips.","operationId":"list_system_templates_v1_admin_system_templates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/system-templates/{template_id}":{"get":{"tags":["admin"],"summary":"Get System Template","description":"Fetch a single system-org template + inheritance metadata (admin-only).\n\nThe response includes:\n  - parent_template_id, parent_template_name (when this is a child)\n  - child_count (when this is a parent)\n  - inherited_fields — list of field paths the UI should render read-only\n    with an \"Inherited\" pill (e.g. \"goals\", \"settings.system_instructions\")","operationId":"get_system_template_v1_admin_system_templates__template_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["admin"],"summary":"Update System Template","description":"Update a system-org template's settings, goals, name, or description (admin-only).\n\nBody keys (all optional):\n  - settings: dict — merged into existing settings (shallow merge per top-level key)\n  - goals: list — REPLACES the existing goals array entirely\n  - name: str\n  - description: str\n\nFor CHILD templates (parent_template_id IS NOT NULL): inherited fields\nare read-only and PATCH attempts to change them return 422. Allowed:\nname, description, status, settings.skills (additive list).","operationId":"update_system_template_v1_admin_system_templates__template_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/system-templates/{parent_id}/children":{"get":{"tags":["admin"],"summary":"List System Template Children","description":"List the child templates that inherit from a given system-org parent.\n\nUsed by the parent's detail view to show \"N child templates inherit\nfrom this.\" with quick-jump links.","operationId":"list_system_template_children_v1_admin_system_templates__parent_id__children_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"parent_id","in":"path","required":true,"schema":{"type":"string","title":"Parent Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["admin"],"summary":"Create System Template Child","description":"Create a child template that inherits from a system-org parent.\n\nBody:\n  - name (required, string, must be distinct from parent's name)\n  - description (optional, string)\n\nThe new child:\n  - inherits prompt / goals / outputs / language / phases from the parent\n    (via the runtime resolver — nothing is copied at creation time)\n  - starts with empty `settings.skills` (admin adds extras after creation)\n  - status='draft' (admin publishes when ready)\n  - org_id = SYSTEM_ORG_ID (matches parent's org by definition)\n\nSingle-level invariant: parent must itself be a standalone template\n(parent.parent_template_id IS NULL). If the request targets a child as a\nparent, returns 400.","operationId":"create_system_template_child_v1_admin_system_templates__parent_id__children_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"parent_id","in":"path","required":true,"schema":{"type":"string","title":"Parent Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/system-templates/reseed":{"post":{"tags":["admin"],"summary":"Reseed System Templates","description":"Seed any missing system-org templates (ON CONFLICT DO NOTHING — safe to call repeatedly).","operationId":"reseed_system_templates_v1_admin_system_templates_reseed_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/templates":{"get":{"tags":["admin"],"summary":"List All Templates","description":"List all templates across all orgs.","operationId":"list_all_templates_v1_admin_templates_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"org_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Org Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/system/setup-template":{"get":{"tags":["admin"],"summary":"Get Setup Template","description":"Get the current setup assistant template.","operationId":"get_setup_template_v1_admin_system_setup_template_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"patch":{"tags":["admin"],"summary":"Update Setup Template","description":"Update the setup assistant template goals/instructions/outputs.","operationId":"update_setup_template_v1_admin_system_setup_template_patch","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/system/available-models":{"get":{"tags":["admin"],"summary":"Get Available Models","description":"Fetch available LLM models from configured providers.\n\nEach entry carries a `vision` flag so the admin picker can warn when a\nselected speaker primary can't process screenshare frames.\n\nBody delegates to app.services.llm_models.fetch_available_models so the\norg-auth endpoint at /v1/inheritable-settings/llm-models reuses the\nsame catalog. Keep both call sites in sync.","operationId":"get_available_models_v1_admin_system_available_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/system/config":{"get":{"tags":["admin"],"summary":"Get System Config","description":"Get all system config key-value pairs.","operationId":"get_system_config_v1_admin_system_config_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"patch":{"tags":["admin"],"summary":"Update System Config","description":"Upsert system config key-value pairs.","operationId":"update_system_config_v1_admin_system_config_patch","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/system/tts-voices":{"get":{"tags":["admin"],"summary":"Get Tts Voices Legacy","description":"Legacy Deepgram-only catalog kept for the current admin UI.\n\nThe new multi-provider catalog is served by ``/system/tts-catalog``.","operationId":"get_tts_voices_legacy_v1_admin_system_tts_voices_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/system/tts-catalog":{"get":{"tags":["admin"],"summary":"Get Tts Catalog","description":"Return the multi-provider catalog of available TTS voices.\n\nShape:\n  {\n    \"languages\": {\"en\": \"English\", ...},\n    \"providers\": {\n      \"deepgram\": {\n        \"label\": \"Deepgram\",\n        \"enabled\": true,\n        \"supports_runtime\": true,\n        \"runtime_note\": null,\n        \"reason\": null,\n        \"voices\": [{provider, voice_id, label, language_codes, ...}, ...]\n      },\n      ...\n    }\n  }","operationId":"get_tts_catalog_v1_admin_system_tts_catalog_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/system/tts-preview":{"get":{"tags":["admin"],"summary":"Preview Tts Voice","description":"Generate a short audio preview of a TTS voice.\n\nAccepts the new ``provider``/``voice_id`` form, and the legacy ``model``\nparameter (interpreted as Deepgram) until the admin UI is updated.\n\nIf ``text`` is provided, that phrase is rendered through the chosen\nvoice — this is how the admin phrase-tester auditions arbitrary text\n(punctuation, emphasis markup, etc.) against any voice + language. If\n``text`` is absent, the canned ``PREVIEW_TEXTS[lang]`` greeting is used\n(preserving the legacy voice-picker preview behavior).","operationId":"preview_tts_voice_v1_admin_system_tts_preview_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"lang","in":"query","required":true,"schema":{"type":"string","description":"Language code, e.g. en","title":"Lang"},"description":"Language code, e.g. en"},{"name":"provider","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Provider name (deepgram, elevenlabs, …)","title":"Provider"},"description":"Provider name (deepgram, elevenlabs, …)"},{"name":"voice_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Provider-specific voice id","title":"Voice Id"},"description":"Provider-specific voice id"},{"name":"model","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Legacy: full Deepgram model id","title":"Model"},"description":"Legacy: full Deepgram model id"},{"name":"text","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":500},{"type":"null"}],"description":"Optional phrase to render. When provided, replaces the canned per-language preview text. Used by the admin phrase-tester.","title":"Text"},"description":"Optional phrase to render. When provided, replaces the canned per-language preview text. Used by the admin phrase-tester."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/skills":{"get":{"tags":["admin"],"summary":"List Default Skills","description":"List all system default skills, including system-internal ones.","operationId":"list_default_skills_v1_admin_skills_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["admin"],"summary":"Create Default Skill","description":"Create a new system default skill. Pass is_system_internal=true to hide from the user-facing skills hub.","operationId":"create_default_skill_v1_admin_skills_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/skills/{skill_id}":{"put":{"tags":["admin"],"summary":"Update Default Skill","description":"Update a system default skill.","operationId":"update_default_skill_v1_admin_skills__skill_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin"],"summary":"Delete Default Skill","description":"Delete a system default skill.","operationId":"delete_default_skill_v1_admin_skills__skill_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/skills/{skill_id}/digest":{"post":{"tags":["admin"],"summary":"Regenerate Admin Skill Digest","description":"Regenerate the pre-digest metadata for any skill (admin).","operationId":"regenerate_admin_skill_digest_v1_admin_skills__skill_id__digest_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/skills/{skill_id}/promote":{"post":{"tags":["admin"],"summary":"Promote Skill","description":"Promote any org skill to a system default (visible to all orgs).","operationId":"promote_skill_v1_admin_skills__skill_id__promote_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/skills/{skill_id}/demote":{"post":{"tags":["admin"],"summary":"Demote Skill","description":"Remove system-default status from a skill.","operationId":"demote_skill_v1_admin_skills__skill_id__demote_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/archetypes":{"get":{"tags":["admin"],"summary":"List Default Archetypes","description":"List all system default archetypes, including system-internal ones.","operationId":"list_default_archetypes_v1_admin_archetypes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["admin"],"summary":"Create Default Archetype","description":"Create a new system default archetype.\n\nRequired body fields: name, slug, description, prompt_section.\nOptional: summary, complexity ('light'|'medium'|'heavy'), is_system_internal,\nopening_style ('relational'|'direct'|'brisk'), bridge_directive (str; '' = no bridge).","operationId":"create_default_archetype_v1_admin_archetypes_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/archetypes/{archetype_id}":{"get":{"tags":["admin"],"summary":"Get Default Archetype","description":"Fetch a single archetype by id.","operationId":"get_default_archetype_v1_admin_archetypes__archetype_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"archetype_id","in":"path","required":true,"schema":{"type":"string","title":"Archetype Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["admin"],"summary":"Update Default Archetype","description":"Partial update of a system default archetype.","operationId":"update_default_archetype_v1_admin_archetypes__archetype_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"archetype_id","in":"path","required":true,"schema":{"type":"string","title":"Archetype Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin"],"summary":"Delete Default Archetype","description":"Delete a system default archetype.\n\nTemplates referencing this archetype will have their `archetype_id` set\nto NULL (via ON DELETE SET NULL on the foreign key) — they fall back\nto today's behavior (global_system_prompt only).","operationId":"delete_default_archetype_v1_admin_archetypes__archetype_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"archetype_id","in":"path","required":true,"schema":{"type":"string","title":"Archetype Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/skillsets":{"get":{"tags":["admin"],"summary":"List Admin Skillsets","description":"List all system default skillsets.","operationId":"list_admin_skillsets_v1_admin_skillsets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["admin"],"summary":"Create Admin Skillset","description":"Create a new system default skillset.","operationId":"create_admin_skillset_v1_admin_skillsets_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/skillsets/{skillset_id}":{"put":{"tags":["admin"],"summary":"Update Admin Skillset","description":"Update a system default skillset.","operationId":"update_admin_skillset_v1_admin_skillsets__skillset_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skillset_id","in":"path","required":true,"schema":{"type":"string","title":"Skillset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["admin"],"summary":"Delete Admin Skillset","description":"Delete a system default skillset.","operationId":"delete_admin_skillset_v1_admin_skillsets__skillset_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skillset_id","in":"path","required":true,"schema":{"type":"string","title":"Skillset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/skillsets/{skillset_id}/promote":{"post":{"tags":["admin"],"summary":"Promote Skillset","description":"Promote any org skillset to a system default.","operationId":"promote_skillset_v1_admin_skillsets__skillset_id__promote_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skillset_id","in":"path","required":true,"schema":{"type":"string","title":"Skillset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/skillsets/{skillset_id}/demote":{"post":{"tags":["admin"],"summary":"Demote Skillset","description":"Remove system-default status from a skillset.","operationId":"demote_skillset_v1_admin_skillsets__skillset_id__demote_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skillset_id","in":"path","required":true,"schema":{"type":"string","title":"Skillset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/sessions/import-recorded":{"post":{"tags":["admin"],"summary":"Import Recorded Session","description":"Import an externally-recorded conversation into the product as a closed session.\n\nCreates: persons row → interviews row (imported_from set, status='completed')\n→ sessions row (status='completed', transcript populated) → session_frames\nrows (S3-backed, source='imported').\n\nReturns the created interview_id and session_id so the caller can deep-link\nto /dashboard/interviews/<interview_id>.","operationId":"import_recorded_session_v1_admin_sessions_import_recorded_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportRecordedSession"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/signup":{"post":{"tags":["auth"],"summary":"Signup","description":"Create a fresh org + its owner user. Internal callers only.\n\nThis is the path used by NextAuth when /v1/auth/me reports no user\nAND no claiming org AND no invitation — i.e. a brand-new tenant.","operationId":"signup_v1_auth_signup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SignupResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/me":{"get":{"tags":["auth"],"summary":"Get Me","description":"NextAuth signin callback — resolves identity for this email.\n\nDecision tree documented at the top of this module.","operationId":"get_me_v1_auth_me_get","parameters":[{"name":"email","in":"query","required":true,"schema":{"type":"string","title":"Email"}},{"name":"name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/membership/status":{"get":{"tags":["auth"],"summary":"Get Membership Status","description":"Polled by /awaiting-approval to detect approval state changes.\n\nThis route is in the PENDING_ALLOWLIST so pending users can call it\nwhile waiting. Returns the live status from the DB (not the cached\nJWT) so a freshly-approved user's next poll flips to 'active'.","operationId":"get_membership_status_v1_auth_membership_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MembershipStatusOut"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/accept-invite":{"post":{"tags":["auth"],"summary":"Accept Invite","description":"Server-to-server: consume an invitation for an authenticated user.\n\nCalled by /api/invite/consume on the web side after OAuth returns.\nValidates the token, the bound email, and not-expired/not-revoked.\nCreates the user (or moves an existing pending user into the\ninviting org as active).\n\nInternal-secret gated because the web layer is trusted to have just\ncompleted OAuth — token alone wouldn't be enough proof of identity.","operationId":"accept_invite_v1_auth_accept_invite_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AcceptInviteRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/org":{"get":{"tags":["auth"],"summary":"Get Org","description":"Get the current organization's info.","operationId":"get_org_v1_auth_org_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInfo"}}}}},"security":[{"HTTPBearer":[]}]},"patch":{"tags":["auth"],"summary":"Update Org","description":"Update the organization's name and/or preferred language.\n\nDistinguishes \"field not provided\" from \"field set to null\" via\npydantic's `model_fields_set` — the latter is how the settings UI\nclears `preferred_language` (\"Not set\" → JSON null). Treating None\nas \"not provided\" would swallow the clear and 400.","operationId":"update_org_v1_auth_org_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/api-keys":{"get":{"tags":["auth"],"summary":"List Api Keys","description":"List all active (non-revoked) API keys for the organization.","operationId":"list_api_keys_v1_auth_api_keys_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/ApiKeyOut"},"type":"array","title":"Response List Api Keys V1 Auth Api Keys Get"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["auth"],"summary":"Create Api Key","description":"Create a new API key for the organization. The raw key is returned once and cannot be retrieved later.","operationId":"create_api_key_v1_auth_api_keys_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/api-keys/{key_id}":{"delete":{"tags":["auth"],"summary":"Revoke Api Key","description":"Revoke an API key (soft-delete via revoked_at timestamp).","operationId":"revoke_api_key_v1_auth_api_keys__key_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/auth/cli/start":{"post":{"tags":["auth"],"summary":"Cli Auth Start","description":"Begin a CLI device-authorization session (no auth).\n\nReturns a secret `device_code` (the CLI keeps it and polls with it) and a\nshort `user_code` embedded in the verification URL the user opens.","operationId":"cli_auth_start_v1_auth_cli_start_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliAuthStartResponse"}}}}}}},"/v1/auth/cli/approve":{"post":{"tags":["auth"],"summary":"Cli Auth Approve","description":"Approve a pending CLI session for the authenticated user.\n\nCalled by the /connect page through the web proxy, so the caller is the\nlogged-in user (resolved by get_current_org). Mints a fresh, labeled API\nkey for that user, stamps it onto the session, and marks it approved. The\nraw key is stored on the session only until the CLI's next poll retrieves\nit (single-use), never exposed to the browser.","operationId":"cli_auth_approve_v1_auth_cli_approve_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliAuthApproveRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/auth/cli/poll":{"post":{"tags":["auth"],"summary":"Cli Auth Poll","description":"Poll a CLI session (no auth; the device_code is the bearer secret).\n\nReturns the API key exactly once — on the first poll after approval — then\nnulls it and marks the session consumed. Subsequent polls never re-expose\nit. Expired/unknown sessions report their status so the CLI can stop.","operationId":"cli_auth_poll_v1_auth_cli_poll_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliAuthPollRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CliAuthPollResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates":{"get":{"tags":["templates"],"summary":"List Templates","description":"List all non-archived templates for the current organization.\n\nReturns ONE row per LINEAGE (the active version), not one row per\nversioned-template row. Phase A versioning made every row a specific\nversion; without this filter the list shows v1 + v2 + v3 of the same\ntemplate as separate entries — confusing for users.\n\nIncludes inheritance metadata per row (parent_template_id +\nparent_template_name + child_count) so the list view can show variant\npills + \"↳ variant of [parent]\" subtitles without N+1 calls.","operationId":"list_templates_v1_templates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/TemplateOut"},"type":"array","title":"Response List Templates V1 Templates Get"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["templates"],"summary":"Create Template","description":"Create a new interview template with goals, settings, and output configuration.\n\nValidates the template and rejects with HTTP 422 if any severity='error' rule fires.\nWarnings are returned on the TemplateOut so the template author sees them immediately.","operationId":"create_template_v1_templates_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/templates/default":{"get":{"tags":["templates"],"summary":"Get Default Template","description":"The product-wide default template — a SYSTEM template chosen by admins.\n\nSelection is system-only by design: Roxels admins star a template on\n/dashboard/admin/system-templates, which writes the SYSTEM org's\norganizations.default_template_id. Every org resolves the same default.\nIntegrations that run a conversation without naming a template (e.g. the\nrun-roxels dev skill) call this endpoint. The stored id is the lineage\nroot — the active version is resolved at read time.\n\nNOTE: registered before GET /{template_id} so \"default\" isn't captured\nas a template id.","operationId":"get_default_template_v1_templates_default_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/templates/setup-assistant":{"post":{"tags":["templates"],"summary":"Start Setup Assistant","description":"Start a setup assistant interview to create a template via AI conversation.","operationId":"start_setup_assistant_v1_templates_setup_assistant_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/templates/{template_id}/modify-assistant":{"post":{"tags":["templates"],"summary":"Start Modify Assistant","description":"Start an EDIT-MODE setup assistant call to modify an existing template via AI.\n\nAlways creates a fresh interview + session — never resumes a prior one. The\nedit-mode framing is composed at this layer:\n\n1. The existing template's full JSON is rendered into EDIT_MODE_PREAMBLE\n   and PREPENDED to the Setup Assistant's `system_instructions` (after\n   its own {available_skills} placeholder is resolved). This puts the\n   artifact-under-edit and the \"you are not onboarding from scratch\"\n   framing at the very top of the agent's prompt.\n2. The interview's goals are replaced with EDIT_MODE_GOALS — a single\n   open-ended goal capturing what the user wants changed and why.\n3. interviews.context.edit_mode_template_id = <template_id> tells the\n   webhook (after the call completes) to run the edit-path synthesis\n   and PATCH the existing template, instead of creating a new one.","operationId":"start_modify_assistant_v1_templates__template_id__modify_assistant_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/edit-status":{"get":{"tags":["templates"],"summary":"Get Edit Status","description":"Return the status of the most-recent 'Edit with AI' run on this template.\n\nSurfaces to the template detail page so the user sees:\n  - \"Edit call in progress\" while they (or a teammate) are still on the call\n  - \"Synthesizing changes…\" between call end and the webhook PATCH landing\n  - \"Updated just now\" briefly after synthesis completes, so the user knows\n    to refresh and see the new content\n\nWithout this signal, after the call hangs up the user is left on the\ntemplate detail page with no idea whether anything is happening or whether\ntheir edits made it in. The webhook synthesis can take 10-30s; that's a\nlong silence to give the user with no feedback.\n\nPolls live in the frontend (idle 0s, in-flight states every 3-4s) so this\nendpoint stays a simple read.\n\nState machine (driven by `interviews.status` + recency of completed_at):\n  - in_call: interview.status == 'in_progress'\n  - processing: interview.status in ('processing','processing_failed')\n  - recently_completed: status == 'completed' AND completed_at within 60s\n  - idle: anything older, or no edit interviews ever","operationId":"get_edit_status_v1_templates__template_id__edit_status_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/schedule":{"post":{"tags":["templates"],"summary":"Schedule Interviews","description":"Create interviews for a list of emails and send calendar invites.","operationId":"schedule_interviews_v1_templates__template_id__schedule_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/dispatch-meeting":{"post":{"tags":["templates"],"summary":"Dispatch Template To Meeting","description":"Send the Roxels agent into an external meeting (Google Meet / Zoom /\nTeams) running this template, in the chosen behavior mode. Server-side\nequivalent of scripts/recall_session.py. Delegates to the shared\n`dispatch_meeting_for_template` action so the live (\"join now\") path and\nthe calendar-invite scheduler create sessions identically. Returns the\nids + bot status so the UI can link to the session afterward.","operationId":"dispatch_template_to_meeting_v1_templates__template_id__dispatch_meeting_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DispatchMeetingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/invite-address":{"get":{"tags":["templates"],"summary":"Get Template Invite Address","description":"The template's calendar-invite email address (mint one lazily if\nnone exists). Add this address to a Google Meet / Zoom / Teams calendar\nevent and the agent joins at the scheduled time. The address is a\npersistent bearer capability — anyone an org member invites it alongside\ntriggers a paid bot — so it's only ever returned to authenticated org\nmembers here.","operationId":"get_template_invite_address_v1_templates__template_id__invite_address_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["templates"],"summary":"Revoke Template Invite Address","description":"Disable calendar-invite dispatch for this template (revoke without\nminting a replacement).","operationId":"revoke_template_invite_address_v1_templates__template_id__invite_address_delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/invite-address/rotate":{"post":{"tags":["templates"],"summary":"Rotate Template Invite Address","description":"Revoke the current address and mint a new one. Use if a token may\nhave leaked — previously-shared invites stop working immediately.","operationId":"rotate_template_invite_address_v1_templates__template_id__invite_address_rotate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/scheduled-meetings":{"get":{"tags":["templates"],"summary":"List Template Scheduled Meetings","description":"Upcoming + recent calendar-triggered dispatches for this template.\nSurfaces the runtime behavior (Project Soul §6) so a template author can\nsee exactly which meetings the agent is scheduled to join.","operationId":"list_template_scheduled_meetings_v1_templates__template_id__scheduled_meetings_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/share":{"post":{"tags":["templates"],"summary":"Share Template Link","description":"Generate a join link for a template. No date, no calendar invite.\n\nTwo modes, with very different semantics:\n\n- **With email** (`body.email` set): the link is tied to that specific\n  person via a pre-created interview row. A return click on this URL\n  resumes the conversation (\"welcome back\"). Use when you know who you're\n  sending to — a single recipient. URL shape: `/join/i/<interviewId>`.\n- **Without email** (`body.email is None`): the link is generic. Each\n  click spawns a fresh interview+session so two strangers don't walk\n  into each other's conversation. URL shape: `/join/t/<templateId>`.\n  We do NOT pre-create an interview here — that happens lazily on the\n  first click via `POST /v1/templates/{id}/join-public`.\n\nIf `send_email` is true and an email is provided, the link is emailed as\na plain invitation (no ICS attachment).","operationId":"share_template_link_v1_templates__template_id__share_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareLinkRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/join-public":{"post":{"tags":["templates"],"summary":"Public Template Join","description":"Spawn a fresh interview+session against a template, with no auth.\n\nThis is the entry point for **generic share links** (`/join/t/<templateId>`).\nEach call creates a new anonymous person row, a new interview, and a new\nsession — there is no find-or-create, because we don't know who's clicking\nand we don't want two strangers walking into each other's conversation.\n\nSecurity posture: the template_id is the bearer token (opaque UUID), same\nas how `/v1/interviews/{id}/join` treats the interview_id. The template\nmust exist and have status='active' to be joinable. Org owners revoke\npublic sharing by deactivating the template.","operationId":"public_template_join_v1_templates__template_id__join_public_post","parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicTemplateJoinRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}":{"get":{"tags":["templates"],"summary":"Get Template","description":"Get a template by ID. Admins can access any template.\n\nIncludes inheritance metadata so the UI can render Inherited pills +\nparent link + child-count banner. Non-inheriting templates get\ninheritance.child_count = 0 and parent_template_id = None.","operationId":"get_template_v1_templates__template_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["templates"],"summary":"Update Template","description":"Update template name, description, goals, settings, or status.\n\nFor CHILD templates (parent_template_id IS NOT NULL), inherited fields\nare read-only — they live only on the parent. The backend SILENTLY\nSTRIPS any inherited fields from the PATCH body and proceeds with the\nallowed fields (name, description, status, settings.skills). This is\nforgiving: the existing frontend save flow re-sends every field on\nevery save, even when only `skills` changed. Returning 422 for those\nbreaks the save UX. We log every strip so drift is observable.\n\nAllowed on a child: name, description, status, settings.skills.","operationId":"update_template_v1_templates__template_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["templates"],"summary":"Archive Template","description":"Soft-delete a SPECIFIC VERSION ROW (not the whole lineage).\n\nThe 'template' in the URL is one row of a versioning lineage. This\nendpoint archives THAT row only — sibling versions in the same lineage\nare untouched.\n\nBLOCKED in two cases (each returns 409 with a structured error so the\nUI can render an actionable message):\n\n1. Row has flavored CHILD templates (`parent_template_id = $1`). They\n   would inherit from an archived parent — weird state. Admin must\n   archive or re-parent the children first.\n\n2. Row is the CURRENTLY-ACTIVE version of its lineage AND other\n   versions exist. Deleting the active leaves the lineage with no\n   active version → `resolve_active_version` degrades to a no-op →\n   new sessions could land on archived content. Admin must promote\n   another version first.\n\nAllowed: row is the only version of its lineage AND has no children.\nArchiving it archives the whole lineage — the expected behavior for\ntemplates that were never versioned.","operationId":"archive_template_v1_templates__template_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/children":{"get":{"tags":["templates"],"summary":"List Template Children","description":"List child templates that inherit from this one.\n\nUsed by the parent's detail view to show \"N variants inherit from this\"\nwith quick-jump links. Same-org scoping (admin sees all).","operationId":"list_template_children_v1_templates__template_id__children_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{parent_id}/children":{"post":{"tags":["templates"],"summary":"Create Template Child","description":"Create a child template that inherits from a parent.\n\nBody:\n  - name (required, distinct from parent's name)\n  - description (optional)\n\nSame-org enforced. Single-level inheritance enforced. Child starts with\nempty extras and status='draft' so admin can configure before publishing.","operationId":"create_template_child_v1_templates__parent_id__children_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"parent_id","in":"path","required":true,"schema":{"type":"string","title":"Parent Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/setup-conversation":{"get":{"tags":["templates"],"summary":"Get Setup Conversation","description":"Return the raw onboarding conversation that created this template.\n\nLossless retrieval: transcript(s), chat messages (embedded in transcript),\nframe captures, and attachments. No summarization. Enables the MCP (and\nany downstream tooling) to see exactly what the user said during setup —\nwhich mechanical checks on the configured template can never reconstruct.\n\nThe linkage uses the reverse pointer already written during setup-assistant\nprocessing: interviews.context.created_template_id.\n\nReturns 200 with status='no_seed_interview' when the template was created\noutside the setup-assistant flow (imported, manually created, etc.). That\nis a normal state, not an error.","operationId":"get_setup_conversation_v1_templates__template_id__setup_conversation_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/setup-intent":{"get":{"tags":["templates"],"summary":"Get Setup Intent","description":"Return the structured setup intent captured during onboarding, if any.\n\nEnvelope `status` values:\n  - \"no_setup_intent\": the setup template didn't opt in, or extraction\n    was never queued. Not an error.\n  - \"pending\": extraction is in-flight (Phase 4 runs in a background\n    task after the setup webhook returns).\n  - \"ok\": extraction completed — setup_intent.items[] + notes populated.\n  - \"failed\": extraction errored out; setup_intent.error has the reason.","operationId":"get_setup_intent_v1_templates__template_id__setup_intent_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/integration-shape":{"get":{"tags":["templates"],"summary":"Get Integration Shape","description":"Return the integration_shape proposal/current state for a template.\n\nIntegration shape is a negotiated proposal between the Roxels setup agent\nand the client's coding agent. Roxels drafts it from the onboarding\nconversation; the coding agent revises it against the actual codebase;\nboth sides converge on a confirmed shape before coverage gaps are flagged.","operationId":"get_integration_shape_v1_templates__template_id__integration_shape_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["templates"],"summary":"Revise Integration Shape","description":"Revise the integration_shape.current, logging the reason in revision_log.\n\npatch: fields to merge into integration_shape.current (top-level keys like\n       delivery, surfaces, per_goal_expectations, rationale, open_questions).\nreason: free-text explanation — required. Captured in revision_log so the\n        MCP can detect drift from the Roxels-authored proposal.\n\nStatus transitions: proposed_by_roxels → under_revision on first revision.\nUse POST /integration-shape/confirm to mark as confirmed.","operationId":"revise_integration_shape_v1_templates__template_id__integration_shape_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntegrationShapeRevision"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/integration-shape/confirm":{"post":{"tags":["templates"],"summary":"Confirm Integration Shape","description":"Mark integration_shape as confirmed. Only after this does the MCP's\ncoverage-gap checks escalate to HIGH severity — before confirmation, the\nloop is about negotiating the shape itself.\n\nThe coding agent should only call this once it has verified the shape\nmatches the actual codebase (endpoints exist, frontend callbacks are wired,\nchained flows have real dependencies).","operationId":"confirm_integration_shape_v1_templates__template_id__integration_shape_confirm_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/setup-intent/extract":{"post":{"tags":["templates"],"summary":"Extract Setup Intent Now","description":"Admin/debug endpoint: replay Phase 4 intent extraction on the onboarding\nconversation that created this template, WITHOUT waiting for a new session.\n\nUseful for testing what the extraction would produce for existing templates\n(e.g. the most recent embedded-onboarding result). Records generation_ms so\nwe can gauge whether extraction is fast enough for the end-of-session\ncritical path or needs to move async.\n\nWrites the result to template.settings.setup_intent (replaces existing).","operationId":"extract_setup_intent_now_v1_templates__template_id__setup_intent_extract_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/handoff-prompt/replay":{"post":{"tags":["templates"],"summary":"Replay Handoff Prompt","description":"Queue a handoff-prompt replay and return immediately.\n\nThe actual LLM call runs in a background task (it takes ~30-60s, too long\nfor the ALB's 60s timeout). Poll GET /{template_id}/handoff-prompt/replay\nfor the result — envelope status: pending | ok | failed.\n\nReconstructs the LLM state the speaker had at end-of-call: the ONBOARDING\ntemplate's system_instructions + full seed transcript + current user-template\nstate. Asks Claude to produce EXACTLY the handoff text it would have sent\nvia send_chat_message.\n\nBody (all optional):\n    onboarding_template_id: override the onboarding template whose\n        system_instructions guide the generated prompt. Default: whatever\n        template actually guided the seed interview.\n    seed_interview_id: override the seed interview. Default: the one linked\n        via interviews.context.created_template_id.","operationId":"replay_handoff_prompt_v1_templates__template_id__handoff_prompt_replay_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/HandoffReplayBody"},{"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"}}}}}},"get":{"tags":["templates"],"summary":"Get Handoff Replay","description":"Return the latest handoff-prompt replay result, or {status: 'none'}.","operationId":"get_handoff_replay_v1_templates__template_id__handoff_prompt_replay_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/export":{"get":{"tags":["templates"],"summary":"Export Template","description":"Export a template as JSON (without org-specific IDs).","operationId":"export_template_v1_templates__template_id__export_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/import":{"post":{"tags":["templates"],"summary":"Import Template","description":"Create a new template from an exported JSON payload.","operationId":"import_template_v1_templates_import_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TemplateOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/templates/{template_id}/regenerate-brief":{"post":{"tags":["templates"],"summary":"Regenerate Session Brief","description":"Regenerate the session brief for a template using the current goals and settings.","operationId":"regenerate_session_brief_v1_templates__template_id__regenerate_brief_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/regenerate-tldr":{"post":{"tags":["templates"],"summary":"Regenerate Tldr","description":"Generate or regenerate the structured behavior TLDR for a template.\n\nHeavy synthesis using a strong model (Opus). On-demand only — never auto-\ngenerated on save/create. Persists in interview_templates.tldr.","operationId":"regenerate_tldr_v1_templates__template_id__regenerate_tldr_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/validate":{"get":{"tags":["templates"],"summary":"Validate Template Endpoint","description":"Return structural violations for a template's goals and settings.\n\nChecks: resolved_reference fields reference a registered data_source,\ndata_source endpoint.url is non-empty, output_schema.template is a\ntransformation map, default_params {fieldName} targets exist as sibling\nfields, and items vs item_schema on resolved_reference arrays.\n\nReturns {\"violations\": [...]} — empty list means no structural errors.","operationId":"validate_template_endpoint_v1_templates__template_id__validate_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/test-output":{"post":{"tags":["templates"],"summary":"Test Output","description":"Fire a test for a configured output using realistic dummy data.\n\nFor webhooks: generates sample data matching the schema, POSTs to the URL, returns status + response.\nFor structured: returns a sample extraction matching the schema.","operationId":"test_output_v1_templates__template_id__test_output_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestOutputRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/learnings/record":{"post":{"tags":["templates"],"summary":"Record Learning","description":"Record a learning observation from a manual test (data source or webhook).\n\nFires the same background synthesis tasks as session-end learnings, but with\nmin_failures_for_synthesis=1 — a single intentional test failure is enough signal\nto synthesize a don't rule. Use this after test_data_source or test_output to\nbuild up the knowledge base during template setup, not just after live interviews.","operationId":"record_learning_v1_templates__template_id__learnings_record_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LearningRecordRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/versions":{"get":{"tags":["templates"],"summary":"List Template Versions","description":"List all versions in the lineage that includes this template id.\n\nReturns the lineage rooted at `version_root_id`, ordered by created_at\nascending so the dropdown reads v1 → vN. Each entry includes the minimum\nneeded to render the dropdown: id, name, version_label, is_active_version,\nspeaker_model / advisor_model (Phase B placeholders), created_at.","operationId":"list_template_versions_v1_templates__template_id__versions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["templates"],"summary":"Create Template Version","description":"Clone a template into a new version. The clone is a FULL COPY of all\ncolumns (goals, settings, name+description, skills) PLUS the source's\nattachments (re-pointed at the new template id). The new row joins the\nlineage via `version_root_id` and is inactive by default; admin promotes\nwhen ready.\n\nAttachment rows are duplicated (same file_url — S3 bytes are shared, no\nre-upload needed). Mutating one version's attachment list (add/remove)\nonly affects that version's row; the file in S3 stays referenced by any\nversion that still points at it.\n\nBody (optional):\n    version_label: human label for the new version. Defaults to \"v{N}\"\n        where N is the next sequential number in the lineage.","operationId":"create_template_version_v1_templates__template_id__versions_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","additionalProperties":true},{"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"}}}}}}},"/v1/templates/{template_id}/promote":{"post":{"tags":["templates"],"summary":"Promote Template Version","description":"Promote this version to is_active_version in its lineage.\n\nAtomic: the previous active row is set to is_active=false in the same\ntransaction as the new one is set to is_active=true. The partial unique\nindex protects against races (two concurrent promotes would have one\nfail with a unique-violation; safe).\n\nIn-flight sessions on the previous version stay on it — sessions pin to\na specific version row at session-start, not at promote-time.","operationId":"promote_template_version_v1_templates__template_id__promote_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/version-label":{"patch":{"tags":["templates"],"summary":"Rename Template Version Label","description":"Inline rename of the version label only — separate from PATCH /{id}\nbecause the version label is metadata, not template content. Lets the\nUI render a small inline-edit affordance on the dropdown without\nneeding to send the whole template body.","operationId":"rename_template_version_label_v1_templates__template_id__version_label_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/attachments":{"get":{"tags":["templates"],"summary":"List Attachments","description":"List all attachments for a template.","operationId":"list_attachments_v1_templates__template_id__attachments_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AttachmentOut"},"title":"Response List Attachments V1 Templates  Template Id  Attachments Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["templates"],"summary":"Upload Attachment","description":"Upload a file attachment to a template.\n\n`role` sets the attachment's `file_role` — defaults to 'reference'. The\nvideo-template worker passes 'source' to durably retain the normalized\ntranscript + original source files (the oracle the Audit Lab grades the SOP\nagainst), so they survive job-artifact cleanup and render in Reference Files.\nOnly the upload-time roles are accepted here; 'fillable'/'process_map' are\nassigned later by the classify/extract pipeline, not by the uploader.","operationId":"upload_attachment_v1_templates__template_id__attachments_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_attachment_v1_templates__template_id__attachments_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/attachments/{attachment_id}/content":{"get":{"tags":["templates"],"summary":"Get Attachment Content","description":"The attachment's CURRENT working text — what's actually indexed and served\nto the agent — as opposed to `file_url`, which always points at the original\nupload and never reflects edits (corrections, open-question answers, and the\naudit loop all write to `extracted_text`, not the source file). This is the\nonly way for a template author to visually verify an edit landed: downloading\n`file_url` shows the pristine original forever, by design (see\n`attachment_processor` / `document_indexer` — the S3 object is provenance,\n`extracted_text` is the live document).","operationId":"get_attachment_content_v1_templates__template_id__attachments__attachment_id__content_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/attachments/url":{"post":{"tags":["templates"],"summary":"Add Url Attachment","description":"Add a URL as a reference attachment.","operationId":"add_url_attachment_v1_templates__template_id__attachments_url_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AttachmentOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/test":{"post":{"tags":["templates"],"summary":"Test Template","description":"Create a test interview and session in one shot, returning a join URL\nfor immediate testing.\n\nPhase A versioning behavior — caller decides whether to test the\nspecific version (passed id) or whichever is currently active in the\nlineage:\n\n- Detail page (admin viewing a specific version): passes\n  `pin_specific_version: true` so we test THE selected version even\n  when it's inactive. Lets \"create v2 → test v2 → promote\" work\n  without first making v2 production-live.\n- List view (admin clicked Test on the row): default behavior —\n  `pin_specific_version` is missing/false, we resolve to the active\n  version of the lineage so the test mirrors what real users get.","operationId":"test_template_v1_templates__template_id__test_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","additionalProperties":true},{"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"}}}}}}},"/v1/attachments/{attachment_id}":{"delete":{"tags":["attachments"],"summary":"Delete Attachment","description":"Delete an attachment and its S3 object. Admins can delete from any org.","operationId":"delete_attachment_v1_attachments__attachment_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/attachments/{attachment_id}/reprocess":{"post":{"tags":["attachments"],"summary":"Reprocess Attachment","description":"Re-run the full attachment pipeline on an existing attachment.\n\nTwo use cases:\n  1. Recover a 'failed' row — extraction or a later step crashed, leaving\n     the attachment in a permanent error state. Reprocess re-extracts,\n     re-classifies, and re-indexes from scratch.\n  2. Re-run after schema change — template goals or classifier behavior\n     changed and the attachment's file_role / document_kind should be\n     recomputed.\n\nThe endpoint flips status to 'processing', runs the same `_process_attachment`\nbackground-task body the upload path uses, and returns the freshly-updated\nfile_role + document_kind + form_structure.","operationId":"reprocess_attachment_v1_attachments__attachment_id__reprocess_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/attachments/{attachment_id}/download":{"get":{"tags":["attachments"],"summary":"Download Attachment","description":"Get a presigned download URL for an attachment. Admins can access any org.","operationId":"download_attachment_v1_attachments__attachment_id__download_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/attachments/{attachment_id}/indexing":{"get":{"tags":["attachments"],"summary":"Get Attachment Indexing Status","description":"Read indexing status for the template-editor UI status pill.\n\nSee plans/pending/scalable-document-search.md § \"UI: status pills\".","operationId":"get_attachment_indexing_status_v1_attachments__attachment_id__indexing_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/attachments/{attachment_id}/index-mode":{"patch":{"tags":["attachments"],"summary":"Set Attachment Index Mode","operationId":"set_attachment_index_mode_v1_attachments__attachment_id__index_mode_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IndexModePatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/attachments/{attachment_id}/file-role":{"patch":{"tags":["attachments"],"summary":"Set Attachment File Role","description":"Designate an attachment's role. 'process_map' marks it as the resident\nnavigation map (rendered into the system prompt, never RAG'd); the offline\nmap builder uses this to promote a generated map file. Re-runs indexing so\nrole semantics apply immediately (a non-'reference' role is skipped by the\nindexer, so a map never lands in the retrieval pool).","operationId":"set_attachment_file_role_v1_attachments__attachment_id__file_role_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FileRolePatch"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/modifications":{"get":{"tags":["template-modifications"],"summary":"List Template Modifications","operationId":"list_template_modifications_v1_templates__template_id__modifications_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Template Modifications V1 Templates  Template Id  Modifications Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/modifications/{mod_id}":{"get":{"tags":["template-modifications"],"summary":"Get Template Modification","operationId":"get_template_modification_v1_templates__template_id__modifications__mod_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"mod_id","in":"path","required":true,"schema":{"type":"string","title":"Mod Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Template Modification V1 Templates  Template Id  Modifications  Mod Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/modifications/{mod_id}/revert":{"post":{"tags":["template-modifications"],"summary":"Revert Template Modification","description":"Undo an in-call test correction — restores system_instructions and any SOP\nattachment it touched to their pre-correction text, and marks the correction\n'reverted' so it can be given again in a fresh test call and re-applied under\nwhatever the reconciliation logic does today, without needing a new template.\n\n404 if the run isn't found/isn't this template's; 409 if it isn't a\nrevertible in-call correction, isn't 'succeeded', or the template has\nchanged since (reverting would discard that later change).","operationId":"revert_template_modification_v1_templates__template_id__modifications__mod_id__revert_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"mod_id","in":"path","required":true,"schema":{"type":"string","title":"Mod Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Revert Template Modification V1 Templates  Template Id  Modifications  Mod Id  Revert Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/modifications/active/status":{"get":{"tags":["template-modifications"],"summary":"Get Active Template Modification","description":"Cheap poll target for the \"update in progress\" banner — the template\ndetail page hits this immediately on load (before Modification History\nor Test Corrections have even mounted) so an in-flight run is visible\nfrom the first instant, not just once the user scrolls to find it.","operationId":"get_active_template_modification_v1_templates__template_id__modifications_active_status_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Active Template Modification V1 Templates  Template Id  Modifications Active Status Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/test-corrections":{"get":{"tags":["template-modifications"],"summary":"List Test Corrections","description":"Recent in-call test corrections for this template, newest first.","operationId":"list_test_corrections_v1_templates__template_id__test_corrections_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Test Corrections V1 Templates  Template Id  Test Corrections Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/test-corrections/{correction_id}":{"patch":{"tags":["template-modifications"],"summary":"Dismiss Test Correction","description":"Dismiss a still-captured correction (a false-fire). Only 'captured' rows\ncan be dismissed — once 'applied', the change is already in the template and\nis undone by reverting the modification, not by dismissing here.","operationId":"dismiss_test_correction_v1_templates__template_id__test_corrections__correction_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"correction_id","in":"path","required":true,"schema":{"type":"string","title":"Correction Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Dismiss Test Correction V1 Templates  Template Id  Test Corrections  Correction Id  Patch"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/generate-tests":{"post":{"tags":["template-audit"],"summary":"Generate Audit Tests","description":"Generate + persist the template's audit test set (calibration probes +\nscenarios + fidelity claims). Idempotent — replaces the prior audit-tagged\nset. Returns a summary (counts + category breakdown + uncovered-claim count).","operationId":"generate_audit_tests_v1_templates__template_id__audit_generate_tests_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Generate Audit Tests V1 Templates  Template Id  Audit Generate Tests Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/tests":{"get":{"tags":["template-audit"],"summary":"List Audit Tests","description":"The audit suite's members — calibration probes (with category + split) and\nqualitative scenarios. Powers the test-set view in the Audit Lab.","operationId":"list_audit_tests_v1_templates__template_id__audit_tests_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Audit Tests V1 Templates  Template Id  Audit Tests Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/source-claims":{"get":{"tags":["template-audit"],"summary":"List Source Claims","description":"The fidelity oracle: atomic claims extracted from the SOURCE and whether\neach is covered in the SOP. `uncovered` are candidate sop_gaps (in source,\ndropped by the SOP).","operationId":"list_source_claims_v1_templates__template_id__audit_source_claims_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Source Claims V1 Templates  Template Id  Audit Source Claims Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/pipeline-findings":{"get":{"tags":["template-audit"],"summary":"List Pipeline Findings","description":"Human-reviewable pipeline-improvement findings emitted by audit repairs.\n\nThese rows are evidence for future global pipeline changes; they are not\nautomatically applied to extraction prompts, generation prompts, or code.","operationId":"list_pipeline_findings_v1_templates__template_id__audit_pipeline_findings_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Pipeline Findings V1 Templates  Template Id  Audit Pipeline Findings Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/runs":{"post":{"tags":["template-audit"],"summary":"Start Audit","description":"Enqueue a closed-loop audit. `mode` ∈ {'autonomous','approval'} (default\nautonomous — the creation audit). The refinement worker picks it up; poll the\nreturned id. Rejects if one is already in flight for this template.","operationId":"start_audit_v1_templates__template_id__audit_runs_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"default":{},"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Start Audit V1 Templates  Template Id  Audit Runs Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["template-audit"],"summary":"List Audits","description":"Audit history for the template — newest first. Each row is the headline\n(status, scores, turn count); the detail endpoint carries the full trace.","operationId":"list_audits_v1_templates__template_id__audit_runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Audits V1 Templates  Template Id  Audit Runs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/runs/{audit_id}":{"get":{"tags":["template-audit"],"summary":"Get Audit","description":"Full audit: headline + open questions + the modification trace (turns,\ninsights, actionables — each turn carries its eval_run_id for drill-through).","operationId":"get_audit_v1_templates__template_id__audit_runs__audit_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"audit_id","in":"path","required":true,"schema":{"type":"string","title":"Audit Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Audit V1 Templates  Template Id  Audit Runs  Audit Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/runs/{audit_id}/approve":{"post":{"tags":["template-audit"],"summary":"Approve Audit","description":"Approval-mode: apply the proposed corrections and re-queue the next turn.","operationId":"approve_audit_v1_templates__template_id__audit_runs__audit_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"audit_id","in":"path","required":true,"schema":{"type":"string","title":"Audit Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Approve Audit V1 Templates  Template Id  Audit Runs  Audit Id  Approve Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/runs/{audit_id}/reject":{"post":{"tags":["template-audit"],"summary":"Reject Audit","description":"Approval-mode: discard the proposed corrections and end the audit.","operationId":"reject_audit_v1_templates__template_id__audit_runs__audit_id__reject_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"audit_id","in":"path","required":true,"schema":{"type":"string","title":"Audit Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Reject Audit V1 Templates  Template Id  Audit Runs  Audit Id  Reject Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/runs/{audit_id}/answers":{"post":{"tags":["template-audit"],"summary":"Answer Open Questions Batch","operationId":"answer_open_questions_batch_v1_templates__template_id__audit_runs__audit_id__answers_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"audit_id","in":"path","required":true,"schema":{"type":"string","title":"Audit Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Answer Open Questions Batch V1 Templates  Template Id  Audit Runs  Audit Id  Answers Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/runs/{audit_id}/answer":{"post":{"tags":["template-audit"],"summary":"Answer Open Question","description":"Answer an open question. The answer is absorbed into whichever artifact\nit belongs in — the SOP (default), `system_instructions`, or `goals`, per\nthe question's `target` (set at seeding time, e.g. by the video pipeline's\n`sop_open_questions` stage; missing/unrecognized defaults to 'sop' for\nbackward compatibility) — and logged to Modification History.","operationId":"answer_open_question_v1_templates__template_id__audit_runs__audit_id__answer_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"audit_id","in":"path","required":true,"schema":{"type":"string","title":"Audit Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Answer Open Question V1 Templates  Template Id  Audit Runs  Audit Id  Answer Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/audit/chat":{"post":{"tags":["template-audit"],"summary":"Audit Chat","description":"Conversational understanding of the audit. Stateless: the client sends the\nrunning message list; the server grounds the reply in the live audit context.","operationId":"audit_chat_v1_templates__template_id__audit_chat_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Audit Chat V1 Templates  Template Id  Audit Chat Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/chat":{"get":{"tags":["template-chat"],"summary":"List Chat Messages","operationId":"list_chat_messages_v1_templates__template_id__chat_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Chat Messages V1 Templates  Template Id  Chat Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["template-chat"],"summary":"Send Chat Message","operationId":"send_chat_message_v1_templates__template_id__chat_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatMessageIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Send Chat Message V1 Templates  Template Id  Chat Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/persons":{"get":{"tags":["persons"],"summary":"List Persons","description":"List all persons in the organization, ordered by name.","operationId":"list_persons_v1_persons_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/PersonOut"},"type":"array","title":"Response List Persons V1 Persons Get"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["persons"],"summary":"Create Person","description":"Create a person record for interviewing. Persons persist across interviews.","operationId":"create_person_v1_persons_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/persons/{person_id}":{"get":{"tags":["persons"],"summary":"Get Person","description":"Get a person by ID.","operationId":"get_person_v1_persons__person_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"person_id","in":"path","required":true,"schema":{"type":"string","title":"Person Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["persons"],"summary":"Update Person","description":"Update a person's name, email, phone, or metadata.","operationId":"update_person_v1_persons__person_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"person_id","in":"path","required":true,"schema":{"type":"string","title":"Person Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PersonOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/interviews":{"get":{"tags":["interviews"],"summary":"List Interviews","description":"List interviews with optional filters by template, person, or status.","operationId":"list_interviews_v1_interviews_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Id"}},{"name":"person_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Person Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["interviews"],"summary":"Create Interview","description":"Create a new interview linking a template to a person.","operationId":"create_interview_v1_interviews_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InterviewCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InterviewOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/interviews/{interview_id}":{"get":{"tags":["interviews"],"summary":"Get Interview","description":"Get full interview detail including sessions, moments, outputs, and findings. Admins can access any interview.","operationId":"get_interview_v1_interviews__interview_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"interview_id","in":"path","required":true,"schema":{"type":"string","title":"Interview Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/interviews/{interview_id}/frames":{"get":{"tags":["interviews"],"summary":"Get Interview Frames","description":"Bulk-fetch all moment frames for an interview (lazy-loaded by frontend).","operationId":"get_interview_frames_v1_interviews__interview_id__frames_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"interview_id","in":"path","required":true,"schema":{"type":"string","title":"Interview Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/interviews/{interview_id}/join":{"get":{"tags":["interviews"],"summary":"Get Interview Join Info","description":"Public endpoint — no auth required. Returns LiveKit connection info,\nfinding-or-creating the right session under this interview.\n\nThis is the canonical user-facing entry point for join links. The\ninterview ID is the stable identifier for the conversation across\nmultiple sessions and revisions; sessions are minted on demand.\n\nBranches (delegated to sessions._join_for_interview):\n- Live session present → return it.\n- Last session completed, interview in_progress → spawn continuation\n  with restored committed_goal_state + transcript tail + summary.\n- Interview processing/processing_failed → 409 (transient).\n- Interview completed → 410 unless the template has\n  `settings.allow_re_completion = true`, in which case it re-opens\n  and increments the revision counter.","operationId":"get_interview_join_info_v1_interviews__interview_id__join_get","parameters":[{"name":"interview_id","in":"path","required":true,"schema":{"type":"string","title":"Interview Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/link-preview/{kind}/{id}":{"get":{"tags":["link-preview"],"summary":"Get Link Preview","description":"Return {title, description} for a join/embed link. No auth, no side effects.","operationId":"get_link_preview_v1_link_preview__kind___id__get","parameters":[{"name":"kind","in":"path","required":true,"schema":{"type":"string","title":"Kind"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","title":"Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions":{"get":{"tags":["sessions"],"summary":"List Sessions","description":"List sessions with their parent interview's template/person info.\n\nPer-session cardinality version of `GET /v1/interviews`. The dashboard\n\"Conversations\" list renders this so a continuation call surfaces as its\nown row on the day it happened, instead of being hidden under the parent\ninterview's original row. Click-through still goes to\n`/dashboard/interviews/{interview_id}`.\n\n`status` filters on the parent interview's status (matches the existing\n/v1/interviews behaviour the dashboard buttons already wire to).","operationId":"list_sessions_v1_sessions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Id"}},{"name":"person_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Person Id"}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["sessions"],"summary":"Create Session","description":"Create a session for an interview. Generates a LiveKit room and JWT token with embedded template, goals, skills, and person context.","operationId":"create_session_v1_sessions_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionCreate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/trace":{"post":{"tags":["sessions"],"summary":"Write Trace Event","description":"Fire-and-forget trace event from the agent. Internal-secret auth only.","operationId":"write_trace_event_v1_sessions_internal_trace_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TraceEventPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/phase-events":{"post":{"tags":["sessions"],"summary":"Write Phase Event","description":"Fire-and-forget phase-lifecycle event from the agent. Internal-secret auth.\n\nPowers the in-app Phases Timeline UI on the session detail page and\nserves as queryable observability for debugging multi-phase sessions.\nFailures are swallowed by the agent client; we still return 401 on\nbad auth so misconfigured workers surface in logs immediately.","operationId":"write_phase_event_v1_sessions_internal_phase_events_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PhaseEventPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/phase-events":{"get":{"tags":["sessions"],"summary":"List Phase Events","description":"List phase events for a session, ordered by emission time. Used by\nthe in-app Phases Timeline pane on the session detail page.","operationId":"list_phase_events_v1_sessions__session_id__phase_events_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Phase Events V1 Sessions  Session Id  Phase Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/frames":{"post":{"tags":["sessions"],"summary":"Ingest Session Frames","description":"Continuous-frame ingest from the agent. Internal-secret auth only.\n\nEach frame is uploaded to S3 (full + optional thumb) and inserted as a\n`session_frames` row. Failures per-frame don't fail the whole batch.","operationId":"ingest_session_frames_v1_sessions_internal__session_id__frames_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionFramesPayload"}}}},"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":"List Session Frames Internal","description":"Internal-secret-auth variant of /sessions/{id}/frames for the agent.\n\nSame query semantics + response shape as the public endpoint, but accepts\nthe LiveKit room name (resolved server-side) instead of a UUID and uses\ninternal-secret auth instead of org-scoped Bearer. Used by the agent's\n`review_recent_visuals` tool to fetch frames from prior real user turns\nthat are no longer in the in-memory cache.","operationId":"list_session_frames_internal_v1_sessions_internal__session_id__frames_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"start","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Start"}},{"name":"end","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"End"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":500,"title":"Limit"}},{"name":"sources","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sources"}},{"name":"user_turn_index","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Turn Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/intent-ledger":{"put":{"tags":["sessions"],"summary":"Checkpoint Intent Ledger","description":"Incremental intent-ledger checkpoint from the agent. Internal-secret\nauth. Idempotent full-state write — the agent debounces (~5s) and forces\none final write at flush, so a crash loses seconds of synthesis at most\n(the \"ten-minute rage\" guarantee).","operationId":"checkpoint_intent_ledger_v1_sessions_internal__session_id__intent_ledger_put","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IntentLedgerPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/intent-ledger":{"get":{"tags":["sessions"],"summary":"Get Intent Ledger","description":"Read the intent ledger for a session. Capability-URL semantics: knowing\nthe session UUID is the credential, exactly like the join link that\nexposes the same session's live room. Used by the in-call view (reconnect\nresync / copy fallback) and, later, by the coding-agent skill that pulls\nthe finished prompt.","operationId":"get_intent_ledger_v1_sessions__session_id__intent_ledger_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/intent-ledger/rebuild":{"post":{"tags":["sessions"],"summary":"Rebuild Intent Ledger Route","description":"Re-run the intent scribe offline over this session's stored transcript\n+ frames (docs/intent-streaming.md, \"Durability\"). The recovery path when\nthe live stream was degraded, and the deliberate re-run after editing the\nscribe prompt. Org-authed dashboard action — the session must belong to\nthe caller's org. Synchronous: sessions are short (30s–3min of speech),\nso a rebuild is a handful of LLM calls.","operationId":"rebuild_intent_ledger_route_v1_sessions__session_id__intent_ledger_rebuild_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/frames/at/{captured_at_ms}":{"get":{"tags":["sessions"],"summary":"Get Frame At","description":"Resolve a LOGICAL frame ref ({captured_at_ms}) to the stored frame —\nthe FrameSink resolver seam (docs/intent-streaming.md). Returns a 302 to\na freshly-presigned S3 URL, so references embedded in copied markdown\nstay valid: the presign happens per-fetch, never baked into the artifact.\nCapability-URL semantics (same as the join link). Nearest-match within\n±2s tolerates the agent's capture-vs-persist timing skew.","operationId":"get_frame_at_v1_sessions__session_id__frames_at__captured_at_ms__get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"captured_at_ms","in":"path","required":true,"schema":{"type":"integer","title":"Captured At Ms"}},{"name":"thumb","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Thumb"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/imported-frames":{"get":{"tags":["sessions"],"summary":"List Imported Frames Internal","description":"Agent polls this every few seconds to discover Recall.ai-bridged\nscreenshare frames written by the Phase A WebSocket sink (source='imported').\n\nReturns the newest frames after `since` (a captured_at unix timestamp),\nso the caller advances `since` to the latest `captured_at` it has seen\nand never re-fetches old frames. Internal-secret auth — this is the\nsame channel the agent already uses for /internal/trace + /internal/results.\n\nPhase B of the Recall screen-share bridge: the agent uses the most\nrecent frame returned here to populate its `_latest_frame` field so\nper-turn LLM injection picks up the screen content without needing a\nLiveKit RTC publisher on the backend.","operationId":"list_imported_frames_internal_v1_sessions_internal__session_id__imported_frames_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"since","in":"query","required":false,"schema":{"type":"number","default":0.0,"title":"Since"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":5,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Imported Frames Internal V1 Sessions Internal  Session Id  Imported Frames Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/utterances":{"get":{"tags":["sessions"],"summary":"List Utterances Internal","description":"Agent polls this to discover diarized utterances + participants from\nthe Recall transcript ingest (speaker-identity Phase 0). Same contract\nas /imported-frames: caller advances `since` to the newest started_at\nseen. Participants are returned in full each call (small, and the\nagent needs name updates that arrive after the participant's first\nutterance).","operationId":"list_utterances_internal_v1_sessions_internal__session_id__utterances_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"since","in":"query","required":false,"schema":{"type":"number","default":0.0,"title":"Since"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Utterances Internal V1 Sessions Internal  Session Id  Utterances Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/recall-bot":{"post":{"tags":["sessions"],"summary":"Stamp Recall Bot Internal","description":"Called at bot dispatch to record the Recall bot id on the session.\nThis is both the handle the backend uses to send in-meeting chat and the\nsignal to the agent that this is a Recall-bridged external meeting.","operationId":"stamp_recall_bot_internal_v1_sessions_internal__session_id__recall_bot_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_RecallBotStamp"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Stamp Recall Bot Internal V1 Sessions Internal  Session Id  Recall Bot Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/mode":{"post":{"tags":["sessions"],"summary":"Stamp Mode Internal","description":"Stamp the session's behavior mode + config (behavior-modes). Used by the\ndispatch path to run a session in trainee/observer mode. Mode is immutable\nonce the agent reads it; this must be set before the agent connects.","operationId":"stamp_mode_internal_v1_sessions_internal__session_id__mode_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_ModeStamp"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Stamp Mode Internal V1 Sessions Internal  Session Id  Mode Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/chat":{"get":{"tags":["sessions"],"summary":"List Chat Internal","description":"Agent polls this for inbound in-meeting chat (Recall sessions). Returns\nincoming messages newer than the agent's last-seen rowcount and the\nvenue signal (recall_bot_id) so the agent knows to route OUTBOUND chat\nthrough Recall too. `since_id` is the count already consumed — chat\nvolume is tiny, so a monotonic ordered fetch is simplest and robust.","operationId":"list_chat_internal_v1_sessions_internal__session_id__chat_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"since_id","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Since Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Chat Internal V1 Sessions Internal  Session Id  Chat Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/send-chat":{"post":{"tags":["sessions"],"summary":"Send Chat Internal","description":"Agent calls this to send an in-meeting chat message (Recall sessions).\nThe backend holds the Recall API key + the bot id, so the send happens\nhere, not in the agent container. Records the outgoing message either\nway (delivered reflects whether Recall accepted it).","operationId":"send_chat_internal_v1_sessions_internal__session_id__send_chat_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_SendChatPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Send Chat Internal V1 Sessions Internal  Session Id  Send Chat Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/leave-meeting":{"post":{"tags":["sessions"],"summary":"Leave Meeting Internal","description":"End the external-meeting bridge: tell the Recall bot to leave the call.\n\nCalled when the agent's session ends by ANY path — clean hang-up,\npause-timeout, or an unrecoverable LiveKit disconnect that kills the agent\nprocess. Without it the bot lingers in the meeting as a ghost after the\nagent is gone (session 06114c15: a LiveKit media-node migration killed the\nagent at 16:47:13, but the Recall bot stayed in the Meet until 16:50:21,\nstill on camera and still transcribing into the void).\n\nThe backend owns this — not the agent — because it holds the Recall key and\nthe bot id, and because it must still fire when the agent process is dead.\nIdempotent: a session with no recall_bot_id (a normal, non-bridged call) is\na no-op, and a double-call after the bot already left is harmless.","operationId":"leave_meeting_internal_v1_sessions_internal__session_id__leave_meeting_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Leave Meeting Internal V1 Sessions Internal  Session Id  Leave Meeting Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/corrections":{"post":{"tags":["sessions"],"summary":"Record Correction Internal","description":"Trainee write-through ledger (behavior-modes §3). The agent calls this\nthe MOMENT an overseer utterance is classified — synchronously, before\nabsorption or acknowledgment — so a correction can never be lost to a\ndownstream failure. Returns the row id so the agent can stamp the\nacknowledgment later (PATCH not needed for v1; ack filled by sweep).","operationId":"record_correction_internal_v1_sessions_internal__session_id__corrections_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_CorrectionPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Record Correction Internal V1 Sessions Internal  Session Id  Corrections Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/frames":{"get":{"tags":["sessions"],"summary":"List Session Frames","description":"List captured frames for a session, with presigned S3 URLs for the\nfull-res webp and thumbnail.\n\nDesigned for post-call agents (e.g. a coding agent given the conversation\nlink) that need to reconstruct the visual context of the call alongside\nthe transcript. Frames are ordered oldest-first by `captured_at`.\n\nQuery params:\n  - `start` / `end` — wall-clock window in seconds (agent clock; same\n    timestamps as the transcript). Both optional.\n  - `limit` — max frames to return (default 500, hard cap 2000).\n  - `sources` — comma-separated subset of captured frame sources\n    (`speaking_tick,motion_spike,turn_end,silent_watch,pointer_trace`, etc.).\n  - `user_turn_index` — restrict to frames captured during a specific real\n    user turn. Match against `transcript[].real_user_turn_index` (user rows)\n    or `transcript[].responding_to_user_turn_index` (assistant rows).\n\nEach frame returns presigned URLs valid for 1 hour. Re-call this endpoint\nto refresh URLs.","operationId":"list_session_frames_v1_sessions__session_id__frames_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"start","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Start"}},{"name":"end","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"End"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":500,"title":"Limit"}},{"name":"sources","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sources"}},{"name":"user_turn_index","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Turn Index"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/notes":{"post":{"tags":["sessions"],"summary":"Add Session Note Internal","description":"The agent records a \"note to self\" — an unstructured standing reminder\nthat changes how it behaves for the rest of the conversation (pace/verbosity\nthe user signalled, a constraint, a name correction). Append-only: the agent\nowns the active set in memory and curates it via `supersedes`; this route\npersists each note durably (provenance + the corpus for \"what feedback are\nwe getting\") and rehydrates the agent on reconnect via the GET below.\n\nSuperseding or hitting the agent's soft cap flips `active` to false — we\nnever delete, so the row survives as analysis material and a future hook for\npromoting durable notes to cross-conversation memory (hence person_id).","operationId":"add_session_note_internal_v1_sessions_internal__session_id__notes_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionNotePayload"}}}},"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":"List Session Notes Internal","description":"Active \"notes to self\" for a session, oldest first — the agent calls this\non `on_enter` to rehydrate its standing reminders after a reconnect.","operationId":"list_session_notes_internal_v1_sessions_internal__session_id__notes_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/test-corrections":{"post":{"tags":["sessions"],"summary":"Add Test Correction Internal","description":"The agent captures a live correction during a test-mode call (the tester\ntelling it its CONFIGURED behavior is wrong). Persist-on-detect: one row per\ncorrection; the batch is reconciled and applied to the template at session\nend. Deliberately separate from session_notes so the agent's note-to-self\nledger is untouched. See\nplans/pending/template-patch-agent-and-correction-sources.md.","operationId":"add_test_correction_internal_v1_sessions_internal__session_id__test_corrections_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TestCorrectionPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/{session_id}/extended-thought":{"post":{"tags":["sessions"],"summary":"Upsert Extended Thought Internal","description":"The agent persists its in-flight extended-thought buffer (or its cleared\nstate) so a reconnecting agent resumes mid-delivery instead of dropping the\nremaining beats. One row per session, upserted. `buffer` null = nothing in\nflight. Durability only — the in-memory buffer is the live working copy.","operationId":"upsert_extended_thought_internal_v1_sessions_internal__session_id__extended_thought_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExtendedThoughtPayload"}}}},"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 Extended Thought Internal","description":"The current extended-thought buffer for a session — the agent calls this\non `on_enter` to resume an in-flight thought after a reconnect.","operationId":"get_extended_thought_internal_v1_sessions_internal__session_id__extended_thought_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/trace":{"get":{"tags":["sessions"],"summary":"Get Session Trace","description":"Return all trace events for a session, ordered by sequence.","operationId":"get_session_trace_v1_sessions__session_id__trace_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/results":{"post":{"tags":["sessions"],"summary":"Submit Session Results","description":"Called by the agent worker periodically (checkpoint) and at session end (final).\nNo user auth — uses internal secret.","operationId":"submit_session_results_v1_sessions_internal_results_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionResultPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/understanding":{"post":{"tags":["sessions"],"summary":"Submit Understanding","description":"Called by the agent to forward real-time understanding extractions.\nFires streaming webhooks if configured on the template.","operationId":"submit_understanding_v1_sessions_internal_understanding_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UnderstandingPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/commit":{"post":{"tags":["sessions"],"summary":"Submit Goal Commit","description":"Called by the agent when it commits a goal's state to external integrators.\nThis is the ONLY path that fires external streaming webhooks — per-turn extractions\npersist to goal_state for dashboard preview but never fire externally.","operationId":"submit_goal_commit_v1_sessions_internal_commit_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommitPayload"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/interactions":{"get":{"tags":["sessions"],"summary":"List Session Interactions","description":"Return all external interactions (webhooks, etc.) for a session, sorted chronologically.","operationId":"list_session_interactions_v1_sessions__session_id__interactions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/goal-state":{"get":{"tags":["sessions"],"summary":"Get Session Goal State","description":"Return the live accumulated goal_state for a session (for dashboard polling during active interviews).\nReturns preview (per-turn) state. For committed state see /goal-state/committed.","operationId":"get_session_goal_state_v1_sessions__session_id__goal_state_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/goal-state/committed":{"get":{"tags":["sessions"],"summary":"Get Session Committed Goal State","description":"Return the committed goal_state for a session — only includes goals that have been\nexplicitly committed (with user confirmation or auto-commit at goal transition/session end).","operationId":"get_session_committed_goal_state_v1_sessions__session_id__goal_state_committed_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/internal/cleanup":{"post":{"tags":["sessions"],"summary":"Cleanup Stale Sessions","description":"Clean up sessions stuck as active when the LiveKit room no longer exists.","operationId":"cleanup_stale_sessions_v1_sessions_internal_cleanup_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/sessions/{session_id}":{"get":{"tags":["sessions"],"summary":"Get Session","description":"Get session details by ID.","operationId":"get_session_v1_sessions__session_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/results":{"get":{"tags":["sessions"],"summary":"Get Session Results","description":"Public endpoint — returns interview summary/results for the interviewee to see after the session ends.\nNo auth required (session_id is the auth, same as the join endpoint).\n\nNOTE: This is the OLDER of two duplicate definitions of this route — the\nnewer one above (line ~2581) handles revision-correctness. Because both\nregister the same path, FastAPI uses this one (the last @router.get wins).\nDeduplication is deferred to its own PR; see CHOICES.md.","operationId":"get_session_results_v1_sessions__session_id__results_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/join":{"get":{"tags":["sessions"],"summary":"Get Join Info","description":"Public endpoint — no auth required. Returns the LiveKit connection info for the interviewee.\n\nBack-compat shim: looks up the session, resolves to its interview, and\ndelegates to _join_for_interview. The interview-keyed endpoint\n(GET /v1/interviews/{id}/join) is the canonical entry point — every\njoin URL we now emit points there. This route exists indefinitely so\nlinks already in inboxes / calendars keep working.","operationId":"get_join_info_v1_sessions__session_id__join_get","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/attachments":{"post":{"tags":["sessions"],"summary":"Upload Session Attachment","description":"Public endpoint — upload a file during a live session.\nFor setup assistant interviews, files attach to the template.\nFor regular interviews, files attach to the interview.","operationId":"upload_session_attachment_v1_sessions__session_id__attachments_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_session_attachment_v1_sessions__session_id__attachments_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/attachments/{attachment_id}":{"delete":{"tags":["sessions"],"summary":"Delete Session Attachment","description":"Public endpoint — delete a file uploaded during a live session.","operationId":"delete_session_attachment_v1_sessions__session_id__attachments__attachment_id__delete","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}},{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/complete":{"post":{"tags":["sessions"],"summary":"Complete Session","description":"Mark a session as completed. Called by the agent or manually.","operationId":"complete_session_v1_sessions__session_id__complete_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/feedback":{"post":{"tags":["sessions"],"summary":"Submit Session Feedback","description":"Submit internal feedback (thumbs up/down + optional comment) for a completed session.\nRequires org-level auth — internal team only.","operationId":"submit_session_feedback_v1_sessions__session_id__feedback_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionFeedbackPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/network-stats":{"post":{"tags":["sessions"],"summary":"Submit Session Network Stats","description":"Accept a client-side WebRTC quality rollup for a session.\n\nNo auth required — session_id acts as the authorization, same as join endpoints.\nCalled from the browser at end-of-call (and periodically as a backup) with\na pre-aggregated rollup of inbound/outbound RTP audio stats sampled via\n`RTCPeerConnection.getStats()`.\n\nLast write wins: each call overwrites the stored rollup. The client is\nexpected to send cumulative/aggregate values, not deltas.","operationId":"submit_session_network_stats_v1_sessions__session_id__network_stats_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NetworkStatsPayload"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/sessions/{session_id}/continue":{"post":{"tags":["sessions"],"summary":"Continue Session","description":"Create a continuation session under the SAME interview as the parent.\n\nNo auth required — session_id acts as the authorization, same as join endpoints.\nDelegates to _join_for_interview after resolving session → interview, so\npause-resume goes through the same find-or-create code path as a fresh\n/join click. Terminal states return 400 to preserve the prior contract;\ninterview-keyed callers can pass `allow_re_completion=True` (template setting)\nto opt into Phase 3 re-open behavior instead.","operationId":"continue_session_v1_sessions__session_id__continue_post","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/skills":{"get":{"tags":["skills"],"summary":"List Skills","description":"List skills visible to caller's org: system defaults + org-owned, excluding system-internal.","operationId":"list_skills_v1_skills_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["skills"],"summary":"Create Skill","description":"Create an org-scoped skill.","operationId":"create_skill_v1_skills_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/skills/{skill_id}":{"put":{"tags":["skills"],"summary":"Update Skill","description":"Update an org-owned skill.","operationId":"update_skill_v1_skills__skill_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["skills"],"summary":"Delete Skill","description":"Delete an org-owned skill.","operationId":"delete_skill_v1_skills__skill_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/skills/{skill_id}/digest":{"post":{"tags":["skills"],"summary":"Regenerate Skill Digest","description":"Regenerate the pre-digest metadata for an org-owned skill.","operationId":"regenerate_skill_digest_v1_skills__skill_id__digest_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/skills/{skill_id}/duplicate":{"post":{"tags":["skills"],"summary":"Duplicate Skill","description":"Duplicate a visible skill into the caller's org.","operationId":"duplicate_skill_v1_skills__skill_id__duplicate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skill_id","in":"path","required":true,"schema":{"type":"string","title":"Skill Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/skillsets":{"get":{"tags":["skillsets"],"summary":"List Skillsets","description":"List skillsets visible to caller's org: system defaults + org-owned.","operationId":"list_skillsets_v1_skillsets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["skillsets"],"summary":"Create Skillset","description":"Create an org-scoped skillset.","operationId":"create_skillset_v1_skillsets_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/skillsets/{skillset_id}":{"put":{"tags":["skillsets"],"summary":"Update Skillset","description":"Update an org-owned skillset.","operationId":"update_skillset_v1_skillsets__skillset_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skillset_id","in":"path","required":true,"schema":{"type":"string","title":"Skillset Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["skillsets"],"summary":"Delete Skillset","description":"Delete an org-owned skillset.","operationId":"delete_skillset_v1_skillsets__skillset_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skillset_id","in":"path","required":true,"schema":{"type":"string","title":"Skillset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/skillsets/{skillset_id}/duplicate":{"post":{"tags":["skillsets"],"summary":"Duplicate Skillset","description":"Duplicate a visible skillset into the caller's org.","operationId":"duplicate_skillset_v1_skillsets__skillset_id__duplicate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"skillset_id","in":"path","required":true,"schema":{"type":"string","title":"Skillset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/archetypes":{"get":{"tags":["archetypes"],"summary":"List Archetypes","description":"List system archetypes visible to any logged-in user.\n\nExcludes archetypes flagged `is_system_internal` (those are for special\ninternal flows that template authors shouldn't pick from). Returns the\nfields the template editor + dashboard need; intentionally omits\n`prompt_section` from the list response (callers don't need the full\nbody when picking; admins use the dedicated admin endpoint to read it).\n`opening_style` / `bridge_directive` are included so the template editor\ncan show the opening posture a template inherits from its archetype.","operationId":"list_archetypes_v1_archetypes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/advisors":{"get":{"tags":["advisors"],"summary":"List Advisors","description":"List advisors owned by caller's org.","operationId":"list_advisors_v1_advisors_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["advisors"],"summary":"Create Advisor","description":"Create an org-scoped advisor.","operationId":"create_advisor_v1_advisors_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/advisors/{advisor_id}":{"put":{"tags":["advisors"],"summary":"Update Advisor","description":"Update an org-owned advisor.","operationId":"update_advisor_v1_advisors__advisor_id__put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"advisor_id","in":"path","required":true,"schema":{"type":"string","title":"Advisor Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["advisors"],"summary":"Delete Advisor","description":"Delete an org-owned advisor.","operationId":"delete_advisor_v1_advisors__advisor_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"advisor_id","in":"path","required":true,"schema":{"type":"string","title":"Advisor Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/embed/keys/{template_id}":{"post":{"tags":["embed"],"summary":"Create Embed Key","description":"Generate a publishable embed key for a template. The raw key is shown only once.\n\nOptionally restrict to specific domains. If allowed_domains is empty, the key works from any domain.","operationId":"create_embed_key_v1_embed_keys__template_id__post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbedKeyCreate","default":{"allowed_domains":[]}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbedKeyCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["embed"],"summary":"List Embed Keys","description":"List embed keys for a template (without raw keys).","operationId":"list_embed_keys_v1_embed_keys__template_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/embed/keys/{key_id}":{"delete":{"tags":["embed"],"summary":"Revoke Embed Key","description":"Revoke an embed key.","operationId":"revoke_embed_key_v1_embed_keys__key_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/embed/sessions/public":{"post":{"tags":["embed"],"summary":"Create Public Session","description":"Create an embed session using a publishable key. No API key needed.\n\nThe template and org are resolved from the embed key.\nIf allowed_domains is set on the key, the request Origin must match.","operationId":"create_public_session_v1_embed_sessions_public_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicSessionCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"options":{"tags":["embed"],"summary":"Public Session Options","description":"CORS preflight for public session creation.","operationId":"public_session_options_v1_embed_sessions_public_options","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/embed/config/public":{"options":{"tags":["embed"],"summary":"Public Config Options","description":"CORS preflight for public embed config fetch.","operationId":"public_config_options_v1_embed_config_public_options","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}},"get":{"tags":["embed"],"summary":"Get Public Embed Config","description":"Resolve an embed key to its launcher / embedded presentation config.\n\nPublic, CORS-enabled, no session created. Returns only safe presentation\nfields — no template content, no goals, no system instructions.","operationId":"get_public_embed_config_v1_embed_config_public_get","parameters":[{"name":"key","in":"query","required":true,"schema":{"type":"string","title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/embed/sessions/{session_id}/context":{"options":{"tags":["embed"],"summary":"Session Context Options","description":"CORS preflight for session context update.","operationId":"session_context_options_v1_embed_sessions__session_id__context_options","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["embed"],"summary":"Update Session Context","description":"Merge additional context into an existing session and regenerate its join token.\n\nCall this from the client side when context is only available at open() time\n(i.e. when using the advanced sessionId flow). Must be called before the user\njoins the room — the updated context is baked into the regenerated join token.","operationId":"update_session_context_v1_embed_sessions__session_id__context_patch","parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SessionContextUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/embed/sessions":{"post":{"tags":["embed"],"summary":"Create Embed Session","description":"Create a person + interview + session in a single call for embed integrations.\n\nReturns the session_id and embed URL ready to pass to the Roxels.open() JS SDK.","operationId":"create_embed_session_v1_embed_sessions_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbedSessionCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbedSessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/events":{"post":{"tags":["events"],"summary":"Log Event","operationId":"log_event_v1_events_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["events"],"summary":"List Events","operationId":"list_events_v1_events_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"}},{"name":"interview_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interview Id"}},{"name":"event_type","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Event Type"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/EventOut"},"title":"Response List Events V1 Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/onboarding/demo-videos":{"get":{"tags":["onboarding"],"summary":"Get Demo Videos","description":"Read curated demo videos shown on the onboarding pre-picker.\n\nReturns `{demo_videos: [{title, description, video_url, thumbnail_url}, ...]}`.\n`clean_demo_videos` drops malformed items so a typo in the admin editor\ncannot break onboarding; an empty result is the disabled state and the\nfrontend hides the third pre-picker path.","operationId":"get_demo_videos_v1_onboarding_demo_videos_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/onboarding/status":{"get":{"tags":["onboarding"],"summary":"Get Onboarding Status","operationId":"get_onboarding_status_v1_onboarding_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingStatus"}}}}},"security":[{"HTTPBearer":[]}]},"patch":{"tags":["onboarding"],"summary":"Patch Onboarding Status","operationId":"patch_onboarding_status_v1_onboarding_status_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingPatch"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/onboarding/complete":{"post":{"tags":["onboarding"],"summary":"Complete Onboarding","operationId":"complete_onboarding_v1_onboarding_complete_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingComplete"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/onboarding/session":{"post":{"tags":["onboarding"],"summary":"Start Onboarding Session","description":"Start a fresh onboarding agent session for this org.\n\nResolves the appropriate specialist template from the provided `kind`.\nDefaults to `generic` if kind is omitted or unrecognized.","operationId":"start_onboarding_session_v1_onboarding_session_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingSessionRequest","default":{}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingSessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/onboarding/discovery":{"post":{"tags":["onboarding"],"summary":"Start Discovery Session","description":"Start a fresh Discovery interview — the brief, empathetic call that runs\nin front of the specialist setup.\n\nOn session end, the discovery template's webhook output fires\n`/v1/webhooks/discovery-handoff`, which creates the next specialist\nonboarding interview pre-filled with prefill_fragments + caller_context +\nproblem_shape and writes a `discovery_handoff` block onto this interview's\ncontext. The frontend polls that block to advance.","operationId":"start_discovery_session_v1_onboarding_discovery_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DiscoverySessionRequest","default":{}}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingSessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/onboarding/audit-timing":{"post":{"tags":["onboarding"],"summary":"Audit Onboarding Timing","description":"Receive a frontend-perceived wait timing and log it.\n\nNo DB write — purely an audit trail. We piggyback on CloudWatch and\ngrep `[audit] timing_perceived` to see the histogram per stage.","operationId":"audit_onboarding_timing_v1_onboarding_audit_timing_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimingAuditRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/onboarding/setup-from-picker":{"post":{"tags":["onboarding"],"summary":"Start Setup From Picker","description":"Skip-discovery entry point. The questionnaire path on /onboarding (and,\nlater, the dashboard \"Create new template\" CTA) calls this to start a setup\ninterview directly without going through a discovery call first.\n\nBuilds the same `interview.context.prefill` shape that the discovery-handoff\nwebhook writes, so the specialist agent's PREFILL AWARENESS / recap behavior\nworks identically regardless of entry path.\n\nIf `surface == \"embedded\"`, attaches the \"Embed Setup Handoff\" skill at\nsession-creation time. Other surfaces don't get the skill — they'll never\nhear MCP / API-key / coding-agent talk during setup.","operationId":"start_setup_from_picker_v1_onboarding_setup_from_picker_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PickerSetupRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OnboardingSessionOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/secrets/prepare":{"post":{"tags":["secrets"],"summary":"Prepare Secret","description":"Create a secret slot and return temporary write-only STS credentials.\nThe MCP client uses these credentials to write the value directly to\nAWS Secrets Manager — this server never sees the plaintext.","operationId":"prepare_secret_v1_secrets_prepare_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrepareRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/secrets/{secret_id}/confirm":{"post":{"tags":["secrets"],"summary":"Confirm Secret","description":"Verify the MCP client wrote a real value, then activate the secret.","operationId":"confirm_secret_v1_secrets__secret_id__confirm_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"secret_id","in":"path","required":true,"schema":{"type":"string","title":"Secret Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/secrets":{"get":{"tags":["secrets"],"summary":"List Secrets","description":"List org's secrets — id, name, description, status only. No values, no ARNs.","operationId":"list_secrets_v1_secrets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["secrets"],"summary":"Direct Store Secret","description":"Store a secret directly. The value is written to AWS Secrets Manager\nimmediately and discarded from memory — it is never logged or stored in the DB.","operationId":"direct_store_secret_v1_secrets_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DirectStoreRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/secrets/{secret_id}/prepare-otp":{"post":{"tags":["secrets"],"summary":"Prepare Otp","description":"Generate a one-time submission URL for non-interactive contexts.","operationId":"prepare_otp_v1_secrets__secret_id__prepare_otp_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"secret_id","in":"path","required":true,"schema":{"type":"string","title":"Secret Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/secrets/{secret_id}":{"patch":{"tags":["secrets"],"summary":"Update Secret","description":"Update the name or description of a secret. Does not change the value.","operationId":"update_secret_v1_secrets__secret_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"secret_id","in":"path","required":true,"schema":{"type":"string","title":"Secret Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["secrets"],"summary":"Delete Secret","description":"Permanently delete a secret. Returns 409 if any templates still reference it.\nRemove those references first, then retry.","operationId":"delete_secret_v1_secrets__secret_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"secret_id","in":"path","required":true,"schema":{"type":"string","title":"Secret Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/secrets/{secret_id}/value":{"put":{"tags":["secrets"],"summary":"Update Secret Value","description":"Replace the value of an existing secret. The new value is written to AWS Secrets Manager\nimmediately and discarded from memory — it is never logged or stored in the DB.","operationId":"update_secret_value_v1_secrets__secret_id__value_put","security":[{"HTTPBearer":[]}],"parameters":[{"name":"secret_id","in":"path","required":true,"schema":{"type":"string","title":"Secret Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateValueRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/secrets/{secret_id}/rotate":{"post":{"tags":["secrets"],"summary":"Rotate Secret","description":"Begin a rotation — returns new temporary write-only STS credentials for the\nsame secret ARN. The MCP client writes the new value directly to Secrets Manager.\nAll templates referencing this secret automatically use the new value.","operationId":"rotate_secret_v1_secrets__secret_id__rotate_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"secret_id","in":"path","required":true,"schema":{"type":"string","title":"Secret Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/setup-assistant":{"post":{"tags":["webhooks"],"summary":"Setup Assistant Webhook","description":"Receive a webhook from the setup assistant's output processor, then fetch\nthe full interview context (transcript + attachments + moments + skills) from\nthe database, run 3 focused Claude phases, and create/update the template.","operationId":"setup_assistant_webhook_v1_webhooks_setup_assistant_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/discovery-handoff":{"post":{"tags":["webhooks"],"summary":"Discovery Handoff Webhook","description":"End-of-Discovery handoff: create the specialist setup interview.\n\nReceives the discovery template's structured-extraction payload at the end\nof the call:\n  {\n    \"event\": \"complete\",\n    \"interview_id\": \"<discovery interview id>\",\n    \"person_name\": \"...\",\n    \"data\": {  # extracted via DISCOVERY_FINDINGS_SCHEMA\n      \"archetype_match\": \"embedded\" | ... | \"not_a_fit\" | \"unsure\",\n      \"caller_context\": \"...\",\n      \"problem_shape\": \"...\",\n      \"surrounding_context\": \"...\",\n      \"pattern_recognized\": \"...\",\n      \"fit_assessment\": {\"verdict\": \"yes|partial|no\", \"reason\": \"...\"},\n      \"readiness_signal\": \"explorer|builder|skeptic\",\n      \"prefill_fragments\": [{\"raw_text\": \"...\", \"context\": \"...\"}, ...],\n    },\n    \"timestamp\": \"...\"\n  }\n\nWrites `context.discovery_handoff` on the discovery interview with one of:\n  {\"status\": \"ready\", \"next_interview_id\": ..., \"next_session_id\": ..., \"archetype_match\": ..., \"kind\": ...}\n  {\"status\": \"not_a_fit\", \"reason\": ...}\n  {\"status\": \"error\", \"reason\": ...}\n\nFrontend polls `GET /api/proxy/interviews/{discoveryInterviewId}` and reads\nthat block to advance.","operationId":"discovery_handoff_webhook_v1_webhooks_discovery_handoff_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/webhooks/livekit/egress":{"post":{"tags":["webhooks"],"summary":"Livekit Egress Webhook","description":"Receive LiveKit egress lifecycle events and reflect them onto the\ncorresponding session row.\n\nLiveKit's webhooks carry a signed JWT in the `Authorization` header. The\n`WebhookReceiver` from `livekit.api` verifies it against our api secret\nand parses the body — never trust the payload before that runs.\n\nEvents we handle:\n  - `egress_started`  → status='active'\n  - `egress_updated`  → status='active' (no-op if already active)\n  - `egress_ended`    → status='completed' on EGRESS_COMPLETE,\n                         status='failed'    on EGRESS_FAILED/ABORTED\n\nUnknown events are 200-OK'd silently — LiveKit retries on non-2xx and\nwe don't want to enter a retry loop over an event we don't model yet.","operationId":"livekit_egress_webhook_v1_webhooks_livekit_egress_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/webhooks/inbound-email":{"post":{"tags":["inbound-email"],"summary":"Inbound Email","description":"Resend Inbound `email.received` webhook. Always 200s; outcomes are\nlogged. See module docstring for the full flow.","operationId":"inbound_email_v1_webhooks_inbound_email_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/diagnostics/templates/{template_id}/recent-sessions":{"get":{"tags":["diagnostics"],"summary":"List Recent Sessions","description":"Return recent sessions for a template with top-level health indicators.","operationId":"list_recent_sessions_v1_diagnostics_templates__template_id__recent_sessions_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":10,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/diagnostics/sessions/{session_id}":{"get":{"tags":["diagnostics"],"summary":"Session Diagnostics","description":"Return a ranked diagnostic report for a single session.","operationId":"session_diagnostics_v1_diagnostics_sessions__session_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/diagnostics/templates/{template_id}/issues":{"get":{"tags":["diagnostics"],"summary":"Template Issues","description":"Return aggregated failure patterns across recent sessions for a template.","operationId":"template_issues_v1_diagnostics_templates__template_id__issues_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Since"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/mcp/status":{"get":{"tags":["mcp"],"summary":"Get Mcp Status","operationId":"get_mcp_status_v1_mcp_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/McpStatus"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/ask":{"post":{"tags":["mcp-qa"],"summary":"Ask","operationId":"ask_v1_ask_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/personas":{"get":{"tags":["evals"],"summary":"List Personas","operationId":"list_personas_v1_admin_eval_personas_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["evals"],"summary":"Create Persona","operationId":"create_persona_v1_admin_eval_personas_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/personas/{persona_id}":{"get":{"tags":["evals"],"summary":"Get Persona","operationId":"get_persona_v1_admin_eval_personas__persona_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"persona_id","in":"path","required":true,"schema":{"type":"string","title":"Persona Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["evals"],"summary":"Update Persona","operationId":"update_persona_v1_admin_eval_personas__persona_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"persona_id","in":"path","required":true,"schema":{"type":"string","title":"Persona Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["evals"],"summary":"Delete Persona","operationId":"delete_persona_v1_admin_eval_personas__persona_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"persona_id","in":"path","required":true,"schema":{"type":"string","title":"Persona Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/briefs":{"get":{"tags":["evals"],"summary":"List Briefs","operationId":"list_briefs_v1_admin_eval_briefs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["evals"],"summary":"Create Brief","operationId":"create_brief_v1_admin_eval_briefs_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/briefs/{brief_id}":{"get":{"tags":["evals"],"summary":"Get Brief","operationId":"get_brief_v1_admin_eval_briefs__brief_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"brief_id","in":"path","required":true,"schema":{"type":"string","title":"Brief Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["evals"],"summary":"Update Brief","operationId":"update_brief_v1_admin_eval_briefs__brief_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"brief_id","in":"path","required":true,"schema":{"type":"string","title":"Brief Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["evals"],"summary":"Delete Brief","operationId":"delete_brief_v1_admin_eval_briefs__brief_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"brief_id","in":"path","required":true,"schema":{"type":"string","title":"Brief Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/probes":{"get":{"tags":["evals"],"summary":"List Probes","operationId":"list_probes_v1_admin_eval_probes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["evals"],"summary":"Create Probe","operationId":"create_probe_v1_admin_eval_probes_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/probes/{probe_id}":{"get":{"tags":["evals"],"summary":"Get Probe","operationId":"get_probe_v1_admin_eval_probes__probe_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"probe_id","in":"path","required":true,"schema":{"type":"string","title":"Probe Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["evals"],"summary":"Update Probe","operationId":"update_probe_v1_admin_eval_probes__probe_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"probe_id","in":"path","required":true,"schema":{"type":"string","title":"Probe Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["evals"],"summary":"Delete Probe","operationId":"delete_probe_v1_admin_eval_probes__probe_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"probe_id","in":"path","required":true,"schema":{"type":"string","title":"Probe Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/probes/{probe_id}/clone":{"post":{"tags":["evals"],"summary":"Clone Probe","description":"Fork a probe. One tricky case can spawn N variants — each clone is an\nindependent row, all setup (including attached_frames) and expectation\ncopied byte-for-byte. The clone records `setup.forked_from` so the lineage\nis visible in the UI.","operationId":"clone_probe_v1_admin_eval_probes__probe_id__clone_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"probe_id","in":"path","required":true,"schema":{"type":"string","title":"Probe Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","additionalProperties":true},{"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"}}}}}}},"/v1/admin/eval/probes/from-session-turn":{"post":{"tags":["evals"],"summary":"Probe From Session Turn","description":"HTTP entry — thin wrapper over the shared impl so the probe runner can\nre-resolve a probe's setup live by calling the same code path without\nFastAPI dependency injection.","operationId":"probe_from_session_turn_v1_admin_eval_probes_from_session_turn_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/probes/{probe_id}/context":{"get":{"tags":["evals"],"summary":"Get Probe Context","description":"Side-context for the probe edit page: recent runs + suite membership.\n\nPowers the \"History & membership\" section at the bottom of ProbeForm:\n  - `recent_runs`: last 10 runs of this probe (reverse-chrono), each\n    with its single eval_run_results row's `rubric_pass` so the UI can\n    render pass/fail dots without a second roundtrip. Run rows that\n    haven't completed (no result yet) report `rubric_pass: null` and\n    the UI shows them as in-flight.\n  - `pass_rate`: `{passed, total, pct}` computed over the same set so\n    the header can show \"7/10 passing (70%)\" without the UI doing math.\n  - `suites`: every eval_suite this probe is currently in, either via\n    explicit_probe_ids OR via tag_query overlap with the probe's tags.\n\nSingle endpoint over two reasons: one network round-trip from the\nedit page, and the two slices conceptually answer the same question\n— \"where does this probe live in the broader testing fabric?\"","operationId":"get_probe_context_v1_admin_eval_probes__probe_id__context_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"probe_id","in":"path","required":true,"schema":{"type":"string","title":"Probe Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/probes/{probe_id}/suite-membership":{"get":{"tags":["evals"],"summary":"Get Probe Suite Membership","description":"All suites + whether this probe is currently in each. Powers the\n\"Add to suite\" modal — one fetch surfaces the full picture so the\nQA can see current memberships and discover suites they could add\nto. `is_explicit` reports membership via `explicit_probe_ids`;\n`tag_match` reports tag-query overlap (informational — adding a\nprobe explicitly to a tag-driven suite is a no-op, but the UI shows\nwhy the toggle reads as on).","operationId":"get_probe_suite_membership_v1_admin_eval_probes__probe_id__suite_membership_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"probe_id","in":"path","required":true,"schema":{"type":"string","title":"Probe Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["evals"],"summary":"Patch Probe Suite Membership","description":"Replace this probe's EXPLICIT suite memberships. Body:\n    { suite_ids: [<id>, ...] }   # the full new explicit-membership list\n\nSuites that gain the probe get it appended to explicit_probe_ids;\nsuites that lose it get it removed. Tag-query memberships are NOT\ntouched — those are a property of the suite's tag_query and the\nprobe's tags, edited elsewhere.\n\nReturns the same shape as GET /probes/{id}/suite-membership so the\nUI can render the post-save state in one round-trip.","operationId":"patch_probe_suite_membership_v1_admin_eval_probes__probe_id__suite_membership_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"probe_id","in":"path","required":true,"schema":{"type":"string","title":"Probe Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/probes/{probe_id}/regenerate-expectation":{"post":{"tags":["evals"],"summary":"Regenerate Probe Expectation","description":"Re-run the expectation generator for an existing probe. Returns the\nproposed expectation text but does NOT persist — the UI shows it next to\nthe current one so the admin can compare before accepting. Persisting is\na separate PATCH so accidental clicks don't blow away hand-edited\nexpectations.","operationId":"regenerate_probe_expectation_v1_admin_eval_probes__probe_id__regenerate_expectation_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"probe_id","in":"path","required":true,"schema":{"type":"string","title":"Probe Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/scenarios":{"get":{"tags":["evals"],"summary":"List Scenarios","operationId":"list_scenarios_v1_admin_eval_scenarios_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["evals"],"summary":"Create Scenario","operationId":"create_scenario_v1_admin_eval_scenarios_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/scenarios/{scenario_id}":{"get":{"tags":["evals"],"summary":"Get Scenario","operationId":"get_scenario_v1_admin_eval_scenarios__scenario_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"scenario_id","in":"path","required":true,"schema":{"type":"string","title":"Scenario Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["evals"],"summary":"Update Scenario","operationId":"update_scenario_v1_admin_eval_scenarios__scenario_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"scenario_id","in":"path","required":true,"schema":{"type":"string","title":"Scenario Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["evals"],"summary":"Delete Scenario","operationId":"delete_scenario_v1_admin_eval_scenarios__scenario_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"scenario_id","in":"path","required":true,"schema":{"type":"string","title":"Scenario Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/suites":{"get":{"tags":["evals"],"summary":"List Suites","operationId":"list_suites_v1_admin_eval_suites_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["evals"],"summary":"Create Suite","operationId":"create_suite_v1_admin_eval_suites_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/suites/{suite_id}":{"get":{"tags":["evals"],"summary":"Get Suite","operationId":"get_suite_v1_admin_eval_suites__suite_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"suite_id","in":"path","required":true,"schema":{"type":"string","title":"Suite Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["evals"],"summary":"Update Suite","operationId":"update_suite_v1_admin_eval_suites__suite_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"suite_id","in":"path","required":true,"schema":{"type":"string","title":"Suite Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["evals"],"summary":"Delete Suite","operationId":"delete_suite_v1_admin_eval_suites__suite_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"suite_id","in":"path","required":true,"schema":{"type":"string","title":"Suite Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/suites/{suite_id}/runs":{"get":{"tags":["evals"],"summary":"List Suite Runs","description":"All parent runs of a suite, reverse-chronological. Lightweight summary\nfor the suite detail page's history table — score + cost only, no\nper-rep results. Click a row to land on /runs/<id> for the full view.","operationId":"list_suite_runs_v1_admin_eval_suites__suite_id__runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"suite_id","in":"path","required":true,"schema":{"type":"string","title":"Suite Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/runs":{"post":{"tags":["evals"],"summary":"Create Run","description":"Trigger a new eval run.\n\nBody shapes:\n    scenario  {\"target\": \"scenario\", \"id\": <uuid>, \"reps\"?: int=1}\n    probe     {\"target\": \"probe\",    \"id\": <uuid>}\n    suite     {\"target\": \"suite\",    \"id\": <uuid>}  -- fans out to children\n    harness   {\"target\": \"harness\",  \"harness_path\": \"tests/replay/test_X.py\"}\n\nCommon optional: \"force_run\": true (bypass the daily cost cap)","operationId":"create_run_v1_admin_eval_runs_post","security":[{"HTTPBearer":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["evals"],"summary":"List Runs","description":"List runs, newest first. Optional `mode` filter: 'logic' or 'latency'.\nReturns r.mode + r.summary_stats so the runs list can show a Mode badge\nand a one-glance latency preview (headline p50/p95) without a second\nrequest per row.","operationId":"list_runs_v1_admin_eval_runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"mode","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/runs/{run_id}":{"get":{"tags":["evals"],"summary":"Get Run","operationId":"get_run_v1_admin_eval_runs__run_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/runs/{run_id}/latency-rows":{"get":{"tags":["evals"],"summary":"Get Run Latency Rows","description":"Return raw per-pass latency rows for a run, ordered by turn then\npass index. Used by the run-detail Latency tab's drilldown view +\nhistogram. For suite-parent runs, fans in across every child probe\nso the parent page shows the full distribution. Returns an empty\nlist for logic runs.","operationId":"get_run_latency_rows_v1_admin_eval_runs__run_id__latency_rows_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/runs/{run_id}/latency-stats":{"get":{"tags":["evals"],"summary":"Get Run Latency Stats","description":"Re-aggregate per-pass latency rows on the fly with arbitrary group_by.\n\n`group_by` is a comma-separated list of dimensions:\n    provider, model, cache_faithfulness, warmup_method,\n    turn_kind.position, turn_kind.has_image, turn_kind.triggers_tools\n\n`include_broken=1` keeps cache_faithfulness=broken rows in the\naggregate (drilldown view). Default 0 = headline view that excludes\nthem. Broken rows are always counted separately and surfaced as\n`broken_count` on each cell.","operationId":"get_run_latency_stats_v1_admin_eval_runs__run_id__latency_stats_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}},{"name":"group_by","in":"query","required":false,"schema":{"type":"string","default":"provider,model,cache_faithfulness","title":"Group By"}},{"name":"include_broken","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Include Broken"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/runs/{run_id}/cancel":{"post":{"tags":["evals"],"summary":"Cancel Run","operationId":"cancel_run_v1_admin_eval_runs__run_id__cancel_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/templates":{"get":{"tags":["evals"],"summary":"List Eval Target Templates","description":"List templates available as eval targets — onboarding specialists from\nsetup_assistant.py + (later) customer templates from the DB.","operationId":"list_eval_target_templates_v1_admin_eval_templates_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/runs/{run_id}/compare":{"get":{"tags":["evals"],"summary":"Compare Runs","description":"Side-by-side compare of two suite runs. Returns aggregate scorecards\nand per-member breakdown so the UI can diff regressed scenarios at a\nglance — the killer view for the cheap-model-test workflow.","operationId":"compare_runs_v1_admin_eval_runs__run_id__compare_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"run_id","in":"path","required":true,"schema":{"type":"string","title":"Run Id"}},{"name":"against","in":"query","required":true,"schema":{"type":"string","title":"Against"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/harnesses":{"get":{"tags":["evals"],"summary":"List Replay Harnesses","description":"List the pytest-based replay harnesses in agent/tests/replay/.\nRead-only: discovery is filesystem-based; harnesses don't live in\nthe DB. Each entry has {path, name, description}; the path is the\ntarget value for POST /runs with target='harness'.","operationId":"list_replay_harnesses_v1_admin_eval_harnesses_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/eval/scenarios/{scenario_id}/runs":{"get":{"tags":["evals"],"summary":"List Scenario Runs","description":"Recent runs for a single scenario — trend view on the scenario detail\npage. Returns rows with enough to render a sparkline: triggered_at,\nstatus, aggregate_metrics (pass_rate), and the run id for click-through.\n\nIncludes BOTH direct scenario-targeted runs AND child runs spawned by\nsuite fanout (since a suite run produces a child eval_runs row with\nscenario_id set), so trends reflect every time this scenario was run\nagainst, regardless of how it was triggered.","operationId":"list_scenario_runs_v1_admin_eval_scenarios__scenario_id__runs_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"scenario_id","in":"path","required":true,"schema":{"type":"string","title":"Scenario Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/draft-from-session/{session_id}":{"post":{"tags":["evals"],"summary":"Post Draft From Session","description":"Reverse-engineer a draft persona + brief from a real prod session.\n\nCalls Claude as judge with strict abstraction discipline (no verbatim\nquotes, category-level facts only). Returns the drafts for admin\nreview — nothing is saved to the DB yet; the UI's \"Save\" buttons POST\nto /personas and /briefs explicitly.","operationId":"post_draft_from_session_v1_admin_eval_draft_from_session__session_id__post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"string","title":"Session Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/eval/grader-prompt":{"get":{"tags":["evals"],"summary":"Get Grader Prompt","description":"Return the current eval-judge system prompt and the code-side\ndefault. Admins edit it via PATCH /v1/admin/system/config on the\n`eval_grader_prompt` key — same surface as other system prompts.","operationId":"get_grader_prompt_v1_admin_eval_grader_prompt_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/internal/eval-replication":{"post":{"tags":["internal-replication"],"summary":"Receive Eval Replication","description":"Apply a peer env's eval-definition mutation to the local DB.\n\nBody shape:\n  { \"action\": \"upsert\" | \"delete\",\n    \"table\":  <one of REPLICATED_TABLES>,\n    \"id\":     <uuid>,\n    \"row\":    <full row dict for upsert; null for delete> }","operationId":"receive_eval_replication_v1_internal_eval_replication_post","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/inheritable-settings/llm-models":{"get":{"tags":["inheritable-settings"],"summary":"Get Llm Models","description":"Catalog of available LLMs across configured providers, callable by\nany org member. Mirrors GET /v1/admin/system/available-models so the\nInheritableField model_ref picker can render real providers + models\non the org/template Advanced Settings panels without admin auth.\n\nReturns a flat list of {provider, model, name, vision} entries.","operationId":"get_llm_models_v1_inheritable_settings_llm_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/inheritable-settings/tts-preview":{"get":{"tags":["inheritable-settings"],"summary":"Get Tts Preview","description":"Play a canned per-language greeting through the chosen voice.\nPowers the ▶ Play button next to the voice picker on the org and\ntemplate Advanced Settings panels. Same synth logic as the admin\n/system/tts-preview endpoint — extracted to app/services/tts_preview\nso both sides share the per-language phrases and provider routing.\nDoes NOT accept a custom `text` parameter — that surface is admin-only\n(the phrase-tester) to keep this endpoint scoped tightly.","operationId":"get_tts_preview_v1_inheritable_settings_tts_preview_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"lang","in":"query","required":true,"schema":{"type":"string","description":"Language code, e.g. en","title":"Lang"},"description":"Language code, e.g. en"},{"name":"provider","in":"query","required":true,"schema":{"type":"string","description":"Provider name (deepgram, elevenlabs, …)","title":"Provider"},"description":"Provider name (deepgram, elevenlabs, …)"},{"name":"voice_id","in":"query","required":true,"schema":{"type":"string","description":"Provider-specific voice id","title":"Voice Id"},"description":"Provider-specific voice id"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/inheritable-settings/tts-catalog":{"get":{"tags":["inheritable-settings"],"summary":"Get Tts Catalog","description":"Multi-provider catalog of available TTS voices, callable by any org\nmember. Mirrors GET /v1/admin/system/tts-catalog (admin-only) so the\norg/template Advanced Settings InheritableField picker can render\nreal voices without requiring admin auth.\n\nShape: {languages: {code: label}, providers: {name: {label, enabled,\nvoices: [{provider, voice_id, label, language_codes, ...}, ...]}}}","operationId":"get_tts_catalog_v1_inheritable_settings_tts_catalog_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/inheritable-settings/registry":{"get":{"tags":["inheritable-settings"],"summary":"Get Registry","description":"Return registry metadata for every key — type, label, choices,\nactive_scopes, eligible_scopes. The org and template Advanced\nSettings panels filter this list to entries where their scope is\nactive; the admin /system page renders the full list with toggles.","operationId":"get_registry_v1_inheritable_settings_registry_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/inheritable-settings/resolve":{"get":{"tags":["inheritable-settings"],"summary":"Resolve","description":"Resolve every registered setting for the caller's org (always)\nand, optionally, for a specific template. Returns one entry per key:\n{key: {value, source}}. `source` is one of \"template\", \"org\",\n\"system\", \"default\" — used to render \"inherited from X\" labels.","operationId":"resolve_v1_inheritable_settings_resolve_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/inheritable-settings/org":{"patch":{"tags":["inheritable-settings"],"summary":"Patch Org","description":"Merge the given key/value pairs into the org's settings_overrides\nblob. `null` values are preserved (= explicit inherit). Validation:\nevery key must be registered + active at org scope.","operationId":"patch_org_v1_inheritable_settings_org_patch","requestBody":{"content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Body"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/inheritable-settings/org/{key}":{"delete":{"tags":["inheritable-settings"],"summary":"Clear Org","description":"Remove a key from the org's settings_overrides entirely. Resolver\nwill walk past it as if it were never set.","operationId":"clear_org_v1_inheritable_settings_org__key__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/inheritable-settings/template/{template_id}":{"patch":{"tags":["inheritable-settings"],"summary":"Patch Template","operationId":"patch_template_v1_inheritable_settings_template__template_id__patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/inheritable-settings/template/{template_id}/{key}":{"delete":{"tags":["inheritable-settings"],"summary":"Clear Template","operationId":"clear_template_v1_inheritable_settings_template__template_id___key__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}},{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/inheritable-settings/{key}/scopes":{"patch":{"tags":["admin"],"summary":"Update Active Scopes","description":"Set active_scopes for a registered setting. Enforces\nblock-disable-until-cleared: if dropping a scope from the active set\nwould orphan existing overrides, returns 409 with the count and a\nmessage instructing the admin to clear them first.","operationId":"update_active_scopes_v1_admin_inheritable_settings__key__scopes_patch","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/inheritable-settings/{key}/overrides/{scope}":{"get":{"tags":["admin"],"summary":"List Overrides","description":"List rows at `scope` currently overriding `key`. Powers the\n'View overriding orgs/templates' link on the admin /system page.","operationId":"list_overrides_v1_admin_inheritable_settings__key__overrides__scope__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"key","in":"path","required":true,"schema":{"type":"string","title":"Key"}},{"name":"scope","in":"path","required":true,"schema":{"type":"string","title":"Scope"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/invitations":{"get":{"tags":["invitations"],"summary":"List Invitations","description":"List open invitations (not consumed, not revoked, not expired).\n\nDoes NOT include `token` or `token_hash` — those leave the database\nonly once, on creation.","operationId":"list_invitations_v1_invitations_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/InvitationOut"},"type":"array","title":"Response List Invitations V1 Invitations Get"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["invitations"],"summary":"Create Invitation","operationId":"create_invitation_v1_invitations_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationCreate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InvitationCreated"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/invitations/{invitation_id}":{"delete":{"tags":["invitations"],"summary":"Revoke Invitation","operationId":"revoke_invitation_v1_invitations__invitation_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"invitation_id","in":"path","required":true,"schema":{"type":"string","title":"Invitation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/members":{"get":{"tags":["members"],"summary":"List Members","description":"Members visible to everyone in the org (including pending members\nthemselves, so the UI can show \"your status is pending\"). Sorted by\nstatus (pending first, then active, then rejected), then by name.","operationId":"list_members_v1_members_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"$ref":"#/components/schemas/MemberOut"},"type":"array","title":"Response List Members V1 Members Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/members/{user_id}/approve":{"post":{"tags":["members"],"summary":"Approve Member","operationId":"approve_member_v1_members__user_id__approve_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/members/{user_id}/reject":{"post":{"tags":["members"],"summary":"Reject Member","operationId":"reject_member_v1_members__user_id__reject_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/members/{user_id}":{"delete":{"tags":["members"],"summary":"Remove Member","operationId":"remove_member_v1_members__user_id__delete","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/members/{user_id}/role":{"post":{"tags":["members"],"summary":"Update Role","description":"Promote/demote a member. Owners only.\n\nLast-owner invariant: cannot demote the only active owner.","operationId":"update_role_v1_members__user_id__role_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"user_id","in":"path","required":true,"schema":{"type":"string","title":"User Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberRoleUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/org/domain":{"get":{"tags":["organization"],"summary":"Get Domain Claim","description":"Return the current claim and whether the owner's email could\nauto-claim a domain that the org doesn't yet hold.","operationId":"get_domain_claim_v1_org_domain_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["organization"],"summary":"Update Domain Claim","description":"Claim or release the org's domain. Owners only.\n\n- body.domain = null → release the claim (sets domain=NULL).\n- body.domain = \"acme.com\" → claim it. Must be non-generic and not\n  already claimed by another org. The partial unique index is the\n  hard guarantee; this 400 is the friendly error.","operationId":"update_domain_claim_v1_org_domain_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DomainClaimUpdate"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/documents/internal/lookup":{"post":{"tags":["documents"],"summary":"Internal Lookup Documents","description":"Agent-facing lookup endpoint, authorized via internal-secret header.\n\nResolves the session's attachments via the interview→template chain and\ncalls the same retrieval engine the public route uses.\n\nThe agent passes its own `self._session_id`, which is the LiveKit room\nname (not a Postgres UUID). We resolve via `_resolve_session_id` — the\nsame helper /v1/sessions/internal/trace uses — so either form works.","operationId":"internal_lookup_documents_v1_documents_internal_lookup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InternalLookupBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/documents/lookup":{"post":{"tags":["documents"],"summary":"Lookup Documents","description":"Hybrid retrieval against indexed attachments owned by the caller's org.\n\nThe agent (and any client of the org's API key) calls this with the\nattachments attached to the session's template.","operationId":"lookup_documents_v1_documents_lookup_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LookupBody"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/documents":{"get":{"tags":["admin","documents"],"summary":"Admin List Documents","description":"List indexable attachments across all orgs for the admin explorer.","operationId":"admin_list_documents_v1_admin_documents_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/admin/documents/{attachment_id}":{"get":{"tags":["admin","documents"],"summary":"Admin Get Document","operationId":"admin_get_document_v1_admin_documents__attachment_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/documents/{attachment_id}/chunks":{"get":{"tags":["admin","documents"],"summary":"Admin List Chunks","operationId":"admin_list_chunks_v1_admin_documents__attachment_id__chunks_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":200,"title":"Limit"}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","default":0,"title":"Offset"}},{"name":"granularity","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Granularity"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/documents/{attachment_id}/chunks/{chunk_id}":{"get":{"tags":["admin","documents"],"summary":"Admin Get Chunk","operationId":"admin_get_chunk_v1_admin_documents__attachment_id__chunks__chunk_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}},{"name":"chunk_id","in":"path","required":true,"schema":{"type":"string","title":"Chunk Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/documents/{attachment_id}/toc":{"get":{"tags":["admin","documents"],"summary":"Admin Get Toc","operationId":"admin_get_toc_v1_admin_documents__attachment_id__toc_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/documents/{attachment_id}/queries":{"get":{"tags":["admin","documents"],"summary":"Admin List Queries","operationId":"admin_list_queries_v1_admin_documents__attachment_id__queries_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/documents/{attachment_id}/lookup":{"post":{"tags":["admin","documents"],"summary":"Admin Lookup","description":"Run a live lookup against this attachment from the explorer UI.\n\nTagged source='explorer' so production session analytics aren't polluted.","operationId":"admin_lookup_v1_admin_documents__attachment_id__lookup_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminLookupBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/documents/{attachment_id}/reindex":{"post":{"tags":["admin","documents"],"summary":"Admin Reindex","description":"Force a fresh index. Clears content_hash so the indexer doesn't no-op.","operationId":"admin_reindex_v1_admin_documents__attachment_id__reindex_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"attachment_id","in":"path","required":true,"schema":{"type":"string","title":"Attachment Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/video-jobs/uploads":{"post":{"tags":["video-jobs"],"summary":"Create Video Upload","description":"Mint a presigned PUT URL the browser can upload a video directly to.\n\nFlow (PR B3): dashboard calls this → gets `{upload_url, s3_key}`\n→ PUTs the file straight to S3 over XHR (with onprogress for the\nupload progress bar) → then POSTs `/v1/video-jobs` with\n`source_kind='upload'` + the same `s3_key`. Backend never streams\nthe video through itself — 2 GB through a Python uvicorn worker\nwould pin it for minutes.\n\nThe S3 key shape is owned by `video_upload_s3_prefix` in the\nservice module so this minter and the job-create validator both\nagree on the namespace (review-fixup contract from PR #756).\n\nFilename gets sanitized to prevent path-traversal / weird-char\nsurprises in S3 listings — the original filename is also stored\nin the job row as part of the slug.","operationId":"create_video_upload_v1_video_jobs_uploads_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateUploadRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Video Upload V1 Video Jobs Uploads Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/video-jobs":{"get":{"tags":["video-jobs"],"summary":"List Video Jobs","operationId":"list_video_jobs_v1_video_jobs_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response List Video Jobs V1 Video Jobs Get"}}}}},"security":[{"HTTPBearer":[]}]},"post":{"tags":["video-jobs"],"summary":"Create Video Job","description":"Create a placeholder `interview_templates` row (status='processing')\nAND a `video_template_jobs` row pointing at it, in a single transaction.\n\nReturns both the new template_id (for the UI to navigate to) and the\njob row (for the progress page's initial state).","operationId":"create_video_job_v1_video_jobs_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateJobRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Video Job V1 Video Jobs Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"HTTPBearer":[]}]}},"/v1/video-jobs/{job_id}":{"get":{"tags":["video-jobs"],"summary":"Get Video Job","operationId":"get_video_job_v1_video_jobs__job_id__get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Video Job V1 Video Jobs  Job Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/video-jobs/{job_id}/cancel":{"post":{"tags":["video-jobs"],"summary":"Cancel Video Job","operationId":"cancel_video_job_v1_video_jobs__job_id__cancel_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CancelJobRequest"},{"type":"null"}],"title":" Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Cancel Video Job V1 Video Jobs  Job Id  Cancel Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/video-jobs/{job_id}/retry":{"post":{"tags":["video-jobs"],"summary":"Retry Video Job","description":"Re-queue a FAILED job. The worker resumes from the last\nsuccessfully-completed stage (skips stages already `ok`, restores their\noutputs from the S3 checkpoint) rather than restarting from scratch — so\na failure in a late stage doesn't cost the user the whole 20-40 min run\nagain. Only failed jobs are retryable; non-failed ones return 409.","operationId":"retry_video_job_v1_video_jobs__job_id__retry_post","security":[{"HTTPBearer":[]}],"parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CancelJobRequest"},{"type":"null"}],"title":" Req"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Retry Video Job V1 Video Jobs  Job Id  Retry Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/templates/{template_id}/video-job":{"get":{"tags":["video-jobs"],"summary":"Get Video Job For Template","description":"The dashboard's template detail page polls this when a template is\n`status='processing'` — fetching by template_id avoids a round-trip\nto discover the job_id first.\n\nReturns 404 when no job has ever existed for this template, which\nmeans either the template isn't a video-generated one or the job\nrow was deleted (CASCADE from template deletion). The detail page\ntreats 404 as \"fall back to the normal template view.\"","operationId":"get_video_job_for_template_v1_templates__template_id__video_job_get","security":[{"HTTPBearer":[]}],"parameters":[{"name":"template_id","in":"path","required":true,"schema":{"type":"string","title":"Template Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Video Job For Template V1 Templates  Template Id  Video Job Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/system/config/public":{"get":{"tags":["system-config"],"summary":"Get Public System Config","description":"Return ONLY the whitelisted public flags from system_config.\n\nUsed by the dashboard to decide which beta features to render\nentry points for. Any authenticated user can read this; the\ncontract is that only safe-to-expose flags appear in the\n`_PUBLIC_SYSTEM_CONFIG_KEYS` whitelist.\n\nIf a whitelisted key isn't set in `system_config` we return it\nas `false` rather than omit it — that way the frontend can\nbranch on `cfg.foo === true` without a separate \"is the key\nset?\" check.","operationId":"get_public_system_config_v1_system_config_public_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Public System Config V1 System Config Public Get"}}}}},"security":[{"HTTPBearer":[]}]}},"/":{"get":{"summary":"Root","operationId":"root__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/health":{"get":{"summary":"Health","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AcceptInviteRequest":{"properties":{"token":{"type":"string","title":"Token"},"email":{"type":"string","title":"Email"}},"type":"object","required":["token","email"],"title":"AcceptInviteRequest"},"AdminLookupBody":{"properties":{"query":{"type":"string","title":"Query"},"section_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Section Hint"},"top_k":{"type":"integer","title":"Top K","default":5}},"type":"object","required":["query"],"title":"AdminLookupBody"},"ApiKeyCreate":{"properties":{"label":{"type":"string","title":"Label","default":"default"}},"type":"object","title":"ApiKeyCreate"},"ApiKeyCreated":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"label":{"type":"string","title":"Label"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"api_key":{"type":"string","title":"Api Key"}},"type":"object","required":["id","label","created_at","api_key"],"title":"ApiKeyCreated"},"ApiKeyOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"label":{"type":"string","title":"Label"},"last_used_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Used At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","label","created_at"],"title":"ApiKeyOut"},"AskBody":{"properties":{"question":{"type":"string","maxLength":4000,"minLength":3,"title":"Question"},"template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Id","description":"Optional — scopes the answer to a specific template."}},"type":"object","required":["question"],"title":"AskBody"},"AttachmentOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"filename":{"type":"string","title":"Filename"},"file_type":{"type":"string","title":"File Type"},"file_url":{"type":"string","title":"File Url"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"status":{"type":"string","title":"Status"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","filename","file_type","file_url","status","created_at"],"title":"AttachmentOut"},"Body_upload_attachment_v1_templates__template_id__attachments_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"},"role":{"type":"string","title":"Role","default":"reference"}},"type":"object","required":["file"],"title":"Body_upload_attachment_v1_templates__template_id__attachments_post"},"Body_upload_session_attachment_v1_sessions__session_id__attachments_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_session_attachment_v1_sessions__session_id__attachments_post"},"CancelJobRequest":{"properties":{},"type":"object","title":"CancelJobRequest"},"ChatMessageIn":{"properties":{"message":{"type":"string","title":"Message"},"attachment_ids":{"items":{"type":"string"},"type":"array","title":"Attachment Ids","default":[]}},"type":"object","required":["message"],"title":"ChatMessageIn"},"CliAuthApproveRequest":{"properties":{"user_code":{"type":"string","title":"User Code"}},"type":"object","required":["user_code"],"title":"CliAuthApproveRequest"},"CliAuthPollRequest":{"properties":{"device_code":{"type":"string","title":"Device Code"}},"type":"object","required":["device_code"],"title":"CliAuthPollRequest"},"CliAuthPollResponse":{"properties":{"status":{"type":"string","title":"Status"},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key"}},"type":"object","required":["status"],"title":"CliAuthPollResponse"},"CliAuthStartResponse":{"properties":{"device_code":{"type":"string","title":"Device Code"},"user_code":{"type":"string","title":"User Code"},"verification_uri":{"type":"string","title":"Verification Uri"},"interval":{"type":"integer","title":"Interval"},"expires_in":{"type":"integer","title":"Expires In"}},"type":"object","required":["device_code","user_code","verification_uri","interval","expires_in"],"title":"CliAuthStartResponse"},"CommitPayload":{"properties":{"room_name":{"type":"string","title":"Room Name"},"session_id":{"type":"string","title":"Session Id"},"goal_id":{"type":"string","title":"Goal Id"},"commit_id":{"type":"string","title":"Commit Id"},"snapshot_id":{"type":"string","title":"Snapshot Id"},"reason":{"type":"string","title":"Reason"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{},"type":"array"}],"title":"Data"}},"type":"object","required":["room_name","session_id","goal_id","commit_id","snapshot_id","reason","data"],"title":"CommitPayload"},"CreateJobRequest":{"properties":{"source_kind":{"type":"string","title":"Source Kind","description":"One of 'youtube', 'upload', 'gdrive', 'direct_url'. Defaults to 'upload'.","default":"upload"},"sources":{"items":{"$ref":"#/components/schemas/SourceSpec"},"type":"array","title":"Sources","description":"Multi-source corpus: several already-uploaded files of any kind (videos, PDFs, docs, existing SOPs). When provided, supersedes the single source_* fields. Each file is classified and processed by type, then synthesized together into one template."},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url"},"source_s3_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source S3 Key"},"job_slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Job Slug","description":"Optional kebab-case slug. Auto-derived from the source if omitted. Also used as the default template name fragment."},"template_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Name","description":"Optional friendly template name. Defaults to 'Template from <slug>'."},"source_instruction":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Instruction","description":"Optional focusing instruction ('extract the process for doing X'). Scopes synthesis to the requested process; recording content outside that scope is treated as noise. Empty => no scoping."},"run_evals":{"type":"boolean","title":"Run Evals","description":"Whether to run the 3 eval scenarios after template creation.","default":true}},"type":"object","title":"CreateJobRequest"},"CreateUploadRequest":{"properties":{"filename":{"type":"string","title":"Filename","description":"Original filename — used as the slug seed + retained as the S3 key suffix."},"content_type":{"type":"string","title":"Content Type","description":"MIME type the browser will send with the PUT.","default":"video/mp4"}},"type":"object","required":["filename"],"title":"CreateUploadRequest"},"DirectStoreRequest":{"properties":{"name":{"type":"string","title":"Name"},"value":{"type":"string","title":"Value"},"description":{"type":"string","title":"Description","default":""}},"type":"object","required":["name","value"],"title":"DirectStoreRequest"},"DiscoverySessionRequest":{"properties":{"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"}},"type":"object","title":"DiscoverySessionRequest"},"DispatchMeetingRequest":{"properties":{"meeting_url":{"type":"string","title":"Meeting Url"},"mode":{"type":"string","title":"Mode","default":"trainee"},"overseers":{"items":{"type":"string"},"type":"array","title":"Overseers","default":[]},"person_name":{"type":"string","title":"Person Name","default":""}},"type":"object","required":["meeting_url"],"title":"DispatchMeetingRequest"},"DomainClaimUpdate":{"properties":{"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"}},"type":"object","title":"DomainClaimUpdate"},"EmbedKeyCreate":{"properties":{"allowed_domains":{"items":{"type":"string"},"type":"array","title":"Allowed Domains","default":[]}},"type":"object","title":"EmbedKeyCreate"},"EmbedKeyCreated":{"properties":{"id":{"type":"string","title":"Id"},"template_id":{"type":"string","title":"Template Id"},"label":{"type":"string","title":"Label"},"allowed_domains":{"items":{"type":"string"},"type":"array","title":"Allowed Domains"},"created_at":{"type":"string","title":"Created At"},"key":{"type":"string","title":"Key"}},"type":"object","required":["id","template_id","label","allowed_domains","created_at","key"],"title":"EmbedKeyCreated"},"EmbedSessionCreate":{"properties":{"template_id":{"type":"string","title":"Template Id"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Id"},"person_name":{"type":"string","title":"Person Name","default":""},"person_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Person Email"},"person_metadata":{"additionalProperties":true,"type":"object","title":"Person Metadata","default":{}},"channel":{"type":"string","title":"Channel","default":"video"},"context":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Context"}},"type":"object","required":["template_id"],"title":"EmbedSessionCreate"},"EmbedSessionOut":{"properties":{"session_id":{"type":"string","title":"Session Id"},"interview_id":{"type":"string","title":"Interview Id"},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Id"},"embed_url":{"type":"string","title":"Embed Url"}},"type":"object","required":["session_id","interview_id","embed_url"],"title":"EmbedSessionOut"},"EmbeddedSettings":{"properties":{"skip_join_screen":{"type":"boolean","title":"Skip Join Screen","default":true},"auto_close":{"type":"boolean","title":"Auto Close","default":true},"fab_anchor":{"type":"string","title":"Fab Anchor","default":"viewport"},"persist_across_conversations":{"type":"boolean","title":"Persist Across Conversations","default":false}},"additionalProperties":true,"type":"object","title":"EmbeddedSettings"},"EventIn":{"properties":{"event_type":{"type":"string","title":"Event Type"},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"},"interview_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interview Id"},"payload":{"additionalProperties":true,"type":"object","title":"Payload","default":{}}},"type":"object","required":["event_type"],"title":"EventIn"},"EventOut":{"properties":{"id":{"type":"string","title":"Id"},"event_type":{"type":"string","title":"Event Type"},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"},"interview_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interview Id"},"payload":{"additionalProperties":true,"type":"object","title":"Payload"},"occurred_at":{"type":"string","title":"Occurred At"}},"type":"object","required":["id","event_type","session_id","interview_id","payload","occurred_at"],"title":"EventOut"},"ExtendedThoughtPayload":{"properties":{"buffer":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Buffer"}},"type":"object","title":"ExtendedThoughtPayload"},"FileRolePatch":{"properties":{"file_role":{"type":"string","title":"File Role"}},"type":"object","required":["file_role"],"title":"FileRolePatch"},"GoalBase":{"properties":{"id":{"type":"string","title":"Id"},"type":{"type":"string","title":"Type"},"prompt":{"type":"string","title":"Prompt"},"follow_up_depth":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Follow Up Depth"},"schema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Schema"},"walk_through":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Walk Through"},"probing_areas":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Probing Areas"},"entry_points":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Entry Points"},"capture_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Capture Mode"},"track":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Track"},"commit_policy":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Commit Policy"},"invariants":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Invariants"},"extraction_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Extraction Mode"}},"type":"object","required":["id","type","prompt"],"title":"GoalBase"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HandoffReplayBody":{"properties":{"onboarding_template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Onboarding Template Id"},"seed_interview_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Seed Interview Id"}},"type":"object","title":"HandoffReplayBody"},"ImportRecordedSession":{"properties":{"template_id":{"type":"string","title":"Template Id","description":"Template the imported conversation should be scoped to."},"imported_from":{"type":"string","title":"Imported From","description":"Free-form provenance key, e.g. 'video:<job-slug>'. Required — this is what marks the conversation as imported."},"person_name":{"type":"string","title":"Person Name","description":"Display name for the person row this interview hangs off.","default":"Imported recording"},"person_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Person Email"},"leader_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Leader Name","description":"Human label for the speaker mapped to the assistant lane (the one the AI would replicate). Stored on interview.context."},"transcript":{"items":{"$ref":"#/components/schemas/ImportedTurn"},"type":"array","title":"Transcript"},"frames":{"items":{"$ref":"#/components/schemas/ImportedFrame"},"type":"array","title":"Frames","default":[]},"started_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Started At","description":"ISO timestamp of when the original recording was made."},"duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration Seconds"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Arbitrary metadata stored on interview.context.imported."}},"type":"object","required":["template_id","imported_from","transcript"],"title":"ImportRecordedSession","description":"Request body for POST /v1/admin/sessions/import-recorded.\n\nFrames are uploaded inline as base64 for v1 — fine up to a few hundred\nframes per recording. If we need to import recordings with thousands of\nframes later, add a pre-upload step (presigned PUTs) and pass URLs here."},"ImportedFrame":{"properties":{"captured_at":{"type":"number","title":"Captured At","description":"Seconds offset from recording start; matches transcript turn timing."},"data_b64":{"type":"string","title":"Data B64","description":"Base64 of the full-resolution image bytes."},"thumb_b64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumb B64","description":"Optional base64 of a small thumbnail."},"content_type":{"type":"string","title":"Content Type","description":"MIME type of data_b64.","default":"image/webp"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"},"motion_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Motion Score"},"user_turn_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Turn Index","description":"Coarse real-user-turn id; matches transcript turns when present."}},"type":"object","required":["captured_at","data_b64"],"title":"ImportedFrame","description":"A single frame, base64-encoded. Uploaded to S3 and recorded in\n`session_frames` with source='imported'."},"ImportedTurn":{"properties":{"role":{"type":"string","title":"Role","description":"'user' or 'assistant'."},"text":{"type":"string","title":"Text"},"speaker_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Name","description":"Original speaker name from the recording (preserved for multi-party calls)."},"speaker_role":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Role","description":"Original speaker role label (e.g. 'onboarder', 'customer')."},"start_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Start Ms"},"end_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"End Ms"},"real_user_turn_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Real User Turn Index"},"responding_to_user_turn_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Responding To User Turn Index"}},"type":"object","required":["role","text"],"title":"ImportedTurn","description":"A single transcript turn.\n\nFor multi-party calls flattened to bilateral: the chosen leader speaker\nbecomes role='assistant' (the lane the AI would have run); every other\nhuman speaker becomes role='user'. `speaker_name` and `speaker_role`\npreserve the original identity so the dashboard can render\n\"Maria (customer)\" instead of flattening invisibly."},"IndexModePatch":{"properties":{"index_mode":{"type":"string","title":"Index Mode"}},"type":"object","required":["index_mode"],"title":"IndexModePatch"},"IntegrationShapeRevision":{"properties":{"patch":{"additionalProperties":true,"type":"object","title":"Patch"},"reason":{"type":"string","title":"Reason"}},"type":"object","required":["patch","reason"],"title":"IntegrationShapeRevision"},"IntentLedgerPayload":{"properties":{"version":{"type":"integer","title":"Version","default":0},"done":{"type":"boolean","title":"Done","default":false},"blocks":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Blocks","default":[]}},"type":"object","title":"IntentLedgerPayload","description":"Block ledger checkpoint from the IntentScribe (intent-streaming\nsessions — docs/intent-streaming.md). Blocks carry LOGICAL frame refs\n({captured_at_ms}) only; URI resolution happens at read time."},"InternalLookupBody":{"properties":{"session_id":{"type":"string","title":"Session Id"},"query":{"type":"string","title":"Query"},"section_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Section Hint"},"top_k":{"type":"integer","title":"Top K","default":5},"turn_no":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Turn No"},"attachment_ids":{"items":{"type":"string"},"type":"array","title":"Attachment Ids"},"template_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Template Id"}},"type":"object","required":["session_id","query"],"title":"InternalLookupBody"},"InterviewCreate":{"properties":{"template_id":{"type":"string","format":"uuid","title":"Template Id"},"person_id":{"type":"string","format":"uuid","title":"Person Id"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"}},"type":"object","required":["template_id","person_id"],"title":"InterviewCreate"},"InterviewOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"template_id":{"type":"string","format":"uuid","title":"Template Id"},"person_id":{"type":"string","format":"uuid","title":"Person Id"},"status":{"type":"string","title":"Status"},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary"},"findings":{"additionalProperties":true,"type":"object","title":"Findings"},"context":{"additionalProperties":true,"type":"object","title":"Context"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"completed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Completed At"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","template_id","person_id","status","findings","context","created_at"],"title":"InterviewOut"},"InvitationCreate":{"properties":{"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role","default":"member"}},"type":"object","required":["email"],"title":"InvitationCreate"},"InvitationCreated":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role"},"invited_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invited By Email"},"invited_by_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invited By Name"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"consumed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Consumed At"},"token":{"type":"string","title":"Token"},"invite_url":{"type":"string","title":"Invite Url"}},"type":"object","required":["id","email","role","expires_at","created_at","token","invite_url"],"title":"InvitationCreated","description":"Returned once on creation; raw token + URL are surfaced only here."},"InvitationOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"role":{"type":"string","title":"Role"},"invited_by_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invited By Email"},"invited_by_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Invited By Name"},"expires_at":{"type":"string","format":"date-time","title":"Expires At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"revoked_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Revoked At"},"consumed_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Consumed At"}},"type":"object","required":["id","email","role","expires_at","created_at"],"title":"InvitationOut"},"LearningRecordRequest":{"properties":{"type":{"type":"string","title":"Type"},"source_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Name"},"phrase":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phrase"},"success":{"type":"boolean","title":"Success","default":false},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"},"queries_tried":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Queries Tried"},"output_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Output Index"},"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"},"status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Status Code"},"payload":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Payload"},"response_preview":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Response Preview"}},"type":"object","required":["type"],"title":"LearningRecordRequest"},"LookupBody":{"properties":{"attachment_ids":{"items":{"type":"string"},"type":"array","title":"Attachment Ids","description":"Scope retrieval to these attachments. Empty list rejected — the caller must know which docs are in scope."},"query":{"type":"string","title":"Query"},"section_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Section Hint"},"top_k":{"type":"integer","title":"Top K","default":5},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"},"turn_no":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Turn No"}},"type":"object","required":["query"],"title":"LookupBody"},"McpStatus":{"properties":{"connected_ever":{"type":"boolean","title":"Connected Ever"},"last_connected_at":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Connected At"},"connection_count_24h":{"type":"integer","title":"Connection Count 24H"},"connection_count_30d":{"type":"integer","title":"Connection Count 30D"}},"type":"object","required":["connected_ever","last_connected_at","connection_count_24h","connection_count_30d"],"title":"McpStatus"},"MeResponse":{"properties":{"org_id":{"type":"string","title":"Org Id"},"org_name":{"type":"string","title":"Org Name"},"api_key":{"type":"string","title":"Api Key"},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id"},"membership_status":{"type":"string","title":"Membership Status","default":"active"},"role":{"type":"string","title":"Role","default":"owner"},"is_admin":{"type":"boolean","title":"Is Admin","default":false}},"type":"object","required":["org_id","org_name","api_key"],"title":"MeResponse","description":"Response shape for /v1/auth/me — the NextAuth signin callback.\n\nIncludes the org+user identifiers plus the issued web-session api\nkey. `membership_status` drives the frontend's pending redirect\nbehavior; `pending` means the user signed in successfully but is\nawaiting approval (domain auto-join) and should land on\n/awaiting-approval rather than the dashboard."},"MemberOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"email":{"type":"string","title":"Email"},"name":{"type":"string","title":"Name"},"role":{"type":"string","title":"Role"},"membership_status":{"type":"string","title":"Membership Status"},"last_seen_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Last Seen At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"approved_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Approved At"}},"type":"object","required":["id","email","name","role","membership_status","created_at"],"title":"MemberOut"},"MemberRoleUpdate":{"properties":{"role":{"type":"string","title":"Role"}},"type":"object","required":["role"],"title":"MemberRoleUpdate"},"MembershipStatusOut":{"properties":{"status":{"type":"string","title":"Status"},"org_id":{"type":"string","title":"Org Id"},"org_name":{"type":"string","title":"Org Name"}},"type":"object","required":["status","org_id","org_name"],"title":"MembershipStatusOut","description":"Polled by /awaiting-approval to detect approval."},"NetworkStatsLeg":{"properties":{"packets_lost_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Packets Lost Pct"},"concealment_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Concealment Pct"},"jitter_p95_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Jitter P95 Ms"},"jitter_avg_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Jitter Avg Ms"},"rtt_p95_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Rtt P95 Ms"},"freeze_count":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Freeze Count"},"total_freezes_duration_ms":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Total Freezes Duration Ms"},"samples":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Samples"},"duration_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Duration S"},"worst_window":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Worst Window"}},"type":"object","title":"NetworkStatsLeg"},"NetworkStatsPayload":{"properties":{"client_recv":{"anyOf":[{"$ref":"#/components/schemas/NetworkStatsLeg"},{"type":"null"}]},"client_send":{"anyOf":[{"$ref":"#/components/schemas/NetworkStatsLeg"},{"type":"null"}]},"user_agent":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Agent"},"livekit_region":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Livekit Region"},"client_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Client Version"}},"type":"object","title":"NetworkStatsPayload"},"OnboardingComplete":{"properties":{"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path"},"synthesis":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Synthesis"}},"type":"object","title":"OnboardingComplete"},"OnboardingPatch":{"properties":{"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data"}},"type":"object","title":"OnboardingPatch"},"OnboardingSessionOut":{"properties":{"session_id":{"type":"string","title":"Session Id"},"interview_id":{"type":"string","title":"Interview Id"},"join_token":{"type":"string","title":"Join Token"},"room_name":{"type":"string","title":"Room Name"},"livekit_url":{"type":"string","title":"Livekit Url"}},"type":"object","required":["session_id","interview_id","join_token","room_name","livekit_url"],"title":"OnboardingSessionOut"},"OnboardingSessionRequest":{"properties":{"kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Kind"},"picker_questionnaire":{"anyOf":[{"items":{"$ref":"#/components/schemas/PickerQuestionnaireEntry"},"type":"array"},{"type":"null"}],"title":"Picker Questionnaire"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"}},"type":"object","title":"OnboardingSessionRequest"},"OnboardingStatus":{"properties":{"status":{"type":"string","title":"Status"},"data":{"additionalProperties":true,"type":"object","title":"Data"}},"type":"object","required":["status","data"],"title":"OnboardingStatus"},"OrgInfo":{"properties":{"org_id":{"type":"string","format":"uuid","title":"Org Id"},"org_name":{"type":"string","title":"Org Name"},"email":{"type":"string","title":"Email"},"preferred_language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preferred Language"}},"type":"object","required":["org_id","org_name","email"],"title":"OrgInfo"},"OrgUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"preferred_language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preferred Language"}},"type":"object","title":"OrgUpdate"},"PersonCreate":{"properties":{"name":{"type":"string","title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"}},"type":"object","required":["name"],"title":"PersonCreate"},"PersonOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata"},"created_at":{"type":"string","format":"date-time","title":"Created At"}},"type":"object","required":["id","name","metadata","created_at"],"title":"PersonOut"},"PersonUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"phone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phone"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"}},"type":"object","title":"PersonUpdate"},"Phase":{"properties":{"phase_id":{"type":"string","title":"Phase Id"},"kind":{"type":"string","title":"Kind"},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ref"},"inline":{"anyOf":[{"$ref":"#/components/schemas/PhaseInline"},{"type":"null"}]},"bridging_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bridging Instructions"},"display_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Display Name"},"carry_summary":{"type":"boolean","title":"Carry Summary","default":true},"required_goals":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Required Goals"}},"type":"object","required":["phase_id","kind"],"title":"Phase","description":"A phase entry in a template's `phases` array.\n\nEach phase is either a *reference* to another template (single source of\ntruth lives elsewhere; read-only here) or *inline* content (lives in the\nparent template; editable here). The semantic distinction drives editor\nUX: locked icon + deep-link for references, full editor for inline.\n\nSee plans/pending — Memory architecture, Phase resolution, and UI sections\nin `also-the-ui-should-curried-sunrise.md`."},"PhaseEventPayload":{"properties":{"session_id":{"type":"string","title":"Session Id"},"interview_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interview Id"},"phase_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phase Id"},"event_name":{"type":"string","title":"Event Name"},"payload":{"additionalProperties":true,"type":"object","title":"Payload","default":{}}},"type":"object","required":["session_id","event_name"],"title":"PhaseEventPayload","description":"Phases architecture: structured event from the agent at every phase\nlifecycle moment. Internal-secret auth (same as /internal/trace)."},"PhaseInline":{"properties":{"body_instructions":{"type":"string","title":"Body Instructions","default":""},"goals":{"items":{"$ref":"#/components/schemas/GoalBase"},"type":"array","title":"Goals","default":[]},"speaker_skills":{"items":{"type":"string"},"type":"array","title":"Speaker Skills","default":[]},"speaker_skillsets":{"items":{"type":"string"},"type":"array","title":"Speaker Skillsets","default":[]},"advisors":{"items":{"type":"string"},"type":"array","title":"Advisors","default":[]},"data_sources":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Data Sources","default":[]},"outputs":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Outputs","default":[]}},"type":"object","title":"PhaseInline","description":"Inline phase definition — content lives in the parent template, editable\nin place. Unlike a referenced phase, this content is not shared with any\nother template; the parent is its single source of truth."},"PickerQuestionnaireEntry":{"properties":{"question":{"type":"string","title":"Question"},"answer":{"type":"string","title":"Answer"}},"type":"object","required":["question","answer"],"title":"PickerQuestionnaireEntry","description":"One question/answer pair from the pre-call onboarding picker.\n\nCarries the literal question text shown to the user and the literal label\nof the option they clicked, so the agent sees exactly what the user was\nasked and exactly how they responded."},"PickerSetupRequest":{"properties":{"kind":{"type":"string","title":"Kind"},"surface":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Surface"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"},"picker_answers":{"anyOf":[{"items":{"$ref":"#/components/schemas/PickerQuestionnaireEntry"},"type":"array"},{"type":"null"}],"title":"Picker Answers"},"free_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Free Text"},"picker_leaf":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Picker Leaf"}},"type":"object","required":["kind"],"title":"PickerSetupRequest","description":"Body for /v1/onboarding/setup-from-picker.\n\nMirrors the prefill shape that the discovery-handoff webhook writes, but\nsourced from the questionnaire instead of from a discovery transcript.\nThe specialist setup template runs against either source identically; its\nPREFILL AWARENESS prefix collapses empty fields gracefully."},"PrepareRequest":{"properties":{"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description","default":""}},"type":"object","required":["name"],"title":"PrepareRequest"},"PublicSessionCreate":{"properties":{"key":{"type":"string","title":"Key"},"person_name":{"type":"string","title":"Person Name","default":""},"external_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"External Id"},"context":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Context"},"source_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Url"}},"type":"object","required":["key"],"title":"PublicSessionCreate"},"PublicTemplateJoinRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"}},"type":"object","title":"PublicTemplateJoinRequest"},"ScheduleRequest":{"properties":{"emails":{"items":{"type":"string"},"type":"array","title":"Emails"},"scheduled_at":{"type":"string","title":"Scheduled At"},"duration_minutes":{"type":"integer","title":"Duration Minutes","default":30}},"type":"object","required":["emails","scheduled_at"],"title":"ScheduleRequest"},"SessionContextUpdate":{"properties":{"context":{"additionalProperties":true,"type":"object","title":"Context"}},"type":"object","required":["context"],"title":"SessionContextUpdate"},"SessionCreate":{"properties":{"interview_id":{"type":"string","format":"uuid","title":"Interview Id"},"channel":{"type":"string","title":"Channel","default":"video"},"mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mode"},"mode_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Mode Config"}},"type":"object","required":["interview_id"],"title":"SessionCreate"},"SessionFeedbackPayload":{"properties":{"rating":{"type":"integer","title":"Rating"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"}},"type":"object","required":["rating"],"title":"SessionFeedbackPayload"},"SessionFramePayload":{"properties":{"captured_at":{"type":"number","title":"Captured At"},"width":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Width"},"height":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Height"},"motion_score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Motion Score"},"source":{"type":"string","title":"Source","default":"speaking_tick"},"user_turn_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"User Turn Index"},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata"},"full_b64":{"type":"string","title":"Full B64"},"thumb_b64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thumb B64"}},"type":"object","required":["captured_at","full_b64"],"title":"SessionFramePayload"},"SessionFramesPayload":{"properties":{"frames":{"items":{"$ref":"#/components/schemas/SessionFramePayload"},"type":"array","title":"Frames","default":[]}},"type":"object","title":"SessionFramesPayload"},"SessionNotePayload":{"properties":{"id":{"type":"string","title":"Id"},"text":{"type":"string","title":"Text"},"created_turn":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Created Turn"},"raw_args":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Raw Args"},"supersedes":{"items":{"type":"string"},"type":"array","title":"Supersedes","default":[]},"evicted":{"items":{"type":"string"},"type":"array","title":"Evicted","default":[]}},"type":"object","required":["id","text"],"title":"SessionNotePayload"},"SessionOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"interview_id":{"type":"string","format":"uuid","title":"Interview Id"},"channel":{"type":"string","title":"Channel"},"status":{"type":"string","title":"Status"},"join_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Join Url"},"room_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Room Name"},"duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration Seconds"},"started_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Started At"},"ended_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Ended At"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"recording_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording Url"},"recording_status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Recording Status"}},"type":"object","required":["id","interview_id","channel","status","created_at"],"title":"SessionOut"},"SessionResultMoment":{"properties":{"timestamp":{"type":"number","title":"Timestamp"},"user_speech":{"type":"string","title":"User Speech"},"frame_b64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Frame B64"},"zoom_b64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zoom B64"}},"type":"object","required":["timestamp","user_speech"],"title":"SessionResultMoment"},"SessionResultPayload":{"properties":{"room_name":{"type":"string","title":"Room Name"},"transcript":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Transcript","default":[]},"moments":{"items":{"$ref":"#/components/schemas/SessionResultMoment"},"type":"array","title":"Moments","default":[]},"duration_seconds":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Duration Seconds"},"telemetry":{"anyOf":[{"additionalProperties":true,"type":"object"},{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Telemetry"},"cost_breakdown":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cost Breakdown"},"document_data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Document Data"},"is_checkpoint":{"type":"boolean","title":"Is Checkpoint","default":false},"ds_learnings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Ds Learnings"},"paused_timeout":{"type":"boolean","title":"Paused Timeout","default":false}},"type":"object","required":["room_name"],"title":"SessionResultPayload"},"ShareLinkRequest":{"properties":{"email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"send_email":{"type":"boolean","title":"Send Email","default":false},"interview_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interview Id"}},"type":"object","title":"ShareLinkRequest"},"SignupRequest":{"properties":{"org_name":{"type":"string","title":"Org Name"},"email":{"type":"string","title":"Email"}},"type":"object","required":["org_name","email"],"title":"SignupRequest"},"SignupResponse":{"properties":{"org_id":{"type":"string","format":"uuid","title":"Org Id"},"org_name":{"type":"string","title":"Org Name"},"api_key":{"type":"string","title":"Api Key"},"user_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"User Id"},"membership_status":{"type":"string","title":"Membership Status","default":"active"},"role":{"type":"string","title":"Role","default":"owner"},"is_admin":{"type":"boolean","title":"Is Admin","default":false}},"type":"object","required":["org_id","org_name","api_key"],"title":"SignupResponse"},"SourceSpec":{"properties":{"s3_key":{"type":"string","title":"S3 Key"},"filename":{"type":"string","title":"Filename","default":""},"content_type":{"type":"string","title":"Content Type","default":"application/octet-stream"}},"type":"object","required":["s3_key"],"title":"SourceSpec","description":"One uploaded file in a multi-source corpus job. The browser uploads each\nfile to S3 (any type) and reports it back here. `media_kind` is derived\nserver-side from content_type/filename so the worker dispatches correctly —\na PDF is never treated as a video."},"TemplateCreate":{"properties":{"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description","default":""},"goals":{"items":{"$ref":"#/components/schemas/GoalBase"},"type":"array","title":"Goals","default":[]},"settings":{"$ref":"#/components/schemas/TemplateSettings","default":{"greeting":"default","greeting_text":"","language":"en","tone":"friendly-professional","max_session_duration_minutes":30,"allow_screen_share":true,"suggest_screen_sharing":false,"instant_start":false,"multi_session":true,"system_instructions":"","outputs":[],"speaker_skills":[],"speaker_skillsets":[],"advisors":[],"skills":[],"skill_execution_mode":"","data_sources":[],"embedded":{"auto_close":true,"fab_anchor":"viewport","persist_across_conversations":false,"skip_join_screen":true}}},"phases_enabled":{"type":"boolean","title":"Phases Enabled","default":false},"phases":{"items":{"$ref":"#/components/schemas/Phase"},"type":"array","title":"Phases","default":[]},"intro_instructions":{"type":"string","title":"Intro Instructions","default":""},"outro_instructions":{"type":"string","title":"Outro Instructions","default":""},"default_use":{"type":"string","title":"Default Use","default":"standalone"}},"type":"object","required":["name"],"title":"TemplateCreate"},"TemplateOut":{"properties":{"id":{"type":"string","format":"uuid","title":"Id"},"name":{"type":"string","title":"Name"},"description":{"type":"string","title":"Description"},"goals":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Goals"},"settings":{"additionalProperties":true,"type":"object","title":"Settings"},"session_brief":{"type":"string","title":"Session Brief","default":""},"tldr":{"type":"string","title":"Tldr","default":""},"status":{"type":"string","title":"Status"},"is_default":{"type":"boolean","title":"Is Default","default":false},"phases_enabled":{"type":"boolean","title":"Phases Enabled","default":false},"phases":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Phases","default":[]},"intro_instructions":{"type":"string","title":"Intro Instructions","default":""},"outro_instructions":{"type":"string","title":"Outro Instructions","default":""},"default_use":{"type":"string","title":"Default Use","default":"standalone"},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"warnings":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Warnings","default":[]},"parent_template_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Parent Template Id"},"inheritance":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Inheritance"},"created_by":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Created By"},"creator_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Creator Name"},"creator_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Creator Email"},"speaker_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Model"},"advisor_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Advisor Model"},"turn_detector_backend":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Turn Detector Backend"},"archetype_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Archetype Id"},"conversation_count":{"type":"integer","title":"Conversation Count","default":0}},"type":"object","required":["id","name","description","goals","settings","status","created_at","updated_at"],"title":"TemplateOut"},"TemplateSettings":{"properties":{"greeting":{"type":"string","title":"Greeting","default":"default"},"greeting_text":{"type":"string","title":"Greeting Text","default":""},"language":{"type":"string","title":"Language","default":"en"},"tone":{"type":"string","title":"Tone","default":"friendly-professional"},"max_session_duration_minutes":{"type":"integer","title":"Max Session Duration Minutes","default":30},"allow_screen_share":{"type":"boolean","title":"Allow Screen Share","default":true},"suggest_screen_sharing":{"type":"boolean","title":"Suggest Screen Sharing","default":false},"instant_start":{"type":"boolean","title":"Instant Start","default":false},"multi_session":{"type":"boolean","title":"Multi Session","default":true},"system_instructions":{"type":"string","title":"System Instructions","default":""},"outputs":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Outputs","default":[]},"speaker_skills":{"items":{"type":"string"},"type":"array","title":"Speaker Skills","default":[]},"speaker_skillsets":{"items":{"type":"string"},"type":"array","title":"Speaker Skillsets","default":[]},"advisors":{"items":{"type":"string"},"type":"array","title":"Advisors","default":[]},"skills":{"items":{"type":"string"},"type":"array","title":"Skills","default":[]},"skill_execution_mode":{"type":"string","title":"Skill Execution Mode","default":""},"data_sources":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Data Sources","default":[]},"embedded":{"$ref":"#/components/schemas/EmbeddedSettings"}},"additionalProperties":true,"type":"object","title":"TemplateSettings"},"TemplateUpdate":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"goals":{"anyOf":[{"items":{"$ref":"#/components/schemas/GoalBase"},"type":"array"},{"type":"null"}],"title":"Goals"},"settings":{"anyOf":[{"$ref":"#/components/schemas/TemplateSettings"},{"type":"null"}]},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"is_default":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Is Default"},"learnings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Learnings"},"phases_enabled":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Phases Enabled"},"phases":{"anyOf":[{"items":{"$ref":"#/components/schemas/Phase"},"type":"array"},{"type":"null"}],"title":"Phases"},"intro_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Intro Instructions"},"outro_instructions":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outro Instructions"},"default_use":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Use"},"speaker_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Speaker Model"},"advisor_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Advisor Model"},"turn_detector_backend":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Turn Detector Backend"},"archetype_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Archetype Id"}},"type":"object","title":"TemplateUpdate"},"TestCorrectionPayload":{"properties":{"what_was_wrong":{"type":"string","title":"What Was Wrong"},"how_it_actually_is":{"type":"string","title":"How It Actually Is"},"target_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Target Hint"},"visual_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Visual Context"},"created_turn":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Created Turn"}},"type":"object","required":["what_was_wrong","how_it_actually_is"],"title":"TestCorrectionPayload"},"TestOutputRequest":{"properties":{"output_index":{"type":"integer","title":"Output Index","default":0}},"type":"object","title":"TestOutputRequest"},"TimingAuditRequest":{"properties":{"stage":{"type":"string","title":"Stage"},"wait_ms":{"type":"integer","title":"Wait Ms"},"interview_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Interview Id"},"extra":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Extra"}},"type":"object","required":["stage","wait_ms"],"title":"TimingAuditRequest"},"TraceEventPayload":{"properties":{"id":{"type":"string","title":"Id"},"session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Session Id"},"room_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Room Name"},"turn_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Turn Id"},"sequence":{"type":"integer","title":"Sequence"},"parent_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Parent Id"},"event_type":{"type":"string","title":"Event Type"},"phase":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Phase"},"data":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Data"},"latency_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Latency Ms"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"input_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Input Tokens"},"output_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Output Tokens"},"outcome":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Outcome"},"failure_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Failure Mode"}},"type":"object","required":["id","sequence","event_type"],"title":"TraceEventPayload"},"UnderstandingPayload":{"properties":{"room_name":{"type":"string","title":"Room Name"},"session_id":{"type":"string","title":"Session Id"},"understanding":{"additionalProperties":true,"type":"object","title":"Understanding"}},"type":"object","required":["room_name","session_id","understanding"],"title":"UnderstandingPayload"},"UpdateRequest":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","title":"UpdateRequest"},"UpdateValueRequest":{"properties":{"value":{"type":"string","title":"Value"}},"type":"object","required":["value"],"title":"UpdateValueRequest"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"_CorrectionPayload":{"properties":{"utterance_text":{"type":"string","title":"Utterance Text"},"classification":{"type":"string","title":"Classification"},"overseer_participant_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Overseer Participant Id"},"overseer_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Overseer Name"},"classifier_reasoning":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Classifier Reasoning"},"preceding_agent_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Preceding Agent Text"},"context_snapshot":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Context Snapshot"},"turn_index":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Turn Index"}},"type":"object","required":["utterance_text","classification"],"title":"_CorrectionPayload"},"_ModeStamp":{"properties":{"mode":{"type":"string","title":"Mode"},"mode_config":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Mode Config"}},"type":"object","required":["mode"],"title":"_ModeStamp"},"_RecallBotStamp":{"properties":{"recall_bot_id":{"type":"string","title":"Recall Bot Id"}},"type":"object","required":["recall_bot_id"],"title":"_RecallBotStamp"},"_SendChatPayload":{"properties":{"text":{"type":"string","title":"Text"}},"type":"object","required":["text"],"title":"_SendChatPayload"}},"securitySchemes":{"HTTPBearer":{"type":"http","scheme":"bearer"}}}}