{"openapi":"3.1.0","info":{"title":"AI Gateway TH","description":"\n**AI Gateway TH** — บริการ AI provider สำหรับลูกค้าในประเทศไทย ที่เป็น OpenAI-compatible HTTP API\n\nใช้ทันทีด้วย OpenAI SDK ของภาษาใดก็ได้:\n\n```python\nimport openai\nclient = openai.OpenAI(\n    base_url=\"https://gateway.kiatdamrong.shop/v1\",\n    api_key=\"<bearer-token>\",\n)\n```\n\n## ทำไมต้องใช้เรา (vs OpenAI/Anthropic ตรง)\n\n- **อยู่ในไทย, PDPA-compliant** — government / regulated entity ใช้ได้ตามกฎหมาย (Claude/GPT API ตรงๆ ใช้ไม่ได้)\n- **PII redaction อัตโนมัติ** — Layer 1 regex + Layer 2 Thai heuristic ครอบ NID/phone/email/person/address/postal/school code/local ID ก่อนส่งออกต่างประเทศ\n- **3-tier routing** — LOCAL (Spark ไทย) / CLOUD (Ollama Cloud) / FRONTIER (Claude, Gemini) เลือกตาม sensitivity + cost\n- **Tier-1 visibility** — ทุก response มี `X-Gateway-*` headers + `/v1/audit/{request_id}` ตรวจสอบได้\n- **Smart Thai routing** — `gateway-th` alias route ภาษาไทยไป backend ที่ดีที่สุดอัตโนมัติ (ฟรี + เร็ว)\n\n## Compliance posture\n\nทุก request ตรวจสอบ + บันทึก:\n\n| Header | ความหมาย |\n|---|---|\n| `X-Gateway-PII-Class` | NONE / REDACTABLE / SENSITIVE |\n| `X-Gateway-PII-Counts` | จำนวน PII ต่อ category |\n| `X-Gateway-Redaction-Layers` | layer ที่ active (regex,heuristic-th) |\n| `X-Gateway-Redaction-Ms` | เวลา redact |\n| `X-Gateway-Redacted-Tokens` | จำนวน token ที่ redact |\n| `X-Gateway-Backend-Tier` | tier ที่ serve (local/cloud/frontier) |\n| `X-Gateway-Compliance-Version` | version ของ redaction stack |\n| `X-Gateway-Request-Id` | id สำหรับ audit trail |\n| `X-Gateway-Audit-Url` | url สำหรับ query audit |\n\n## Authentication — Layered (v0.11.0+)\n\n```\nAuthorization: Bearer <JWT>\n```\n\nToken เป็น **JWT (HS256)** มี `iss/sub/iat/exp/scopes/jti`. Default TTL 90 วัน.\nตัวเก่า opaque bearer (`demo-...`) ยังใช้ได้สำหรับ legacy/testing.\n\n| Layer | สิ่งที่ตรวจ | ผลถ้าผิด |\n|---|---|---|\n| 1 | Bearer header | `401 authentication_error` |\n| 2 | JWT signature + exp | `401 invalid_token` / `token_expired` |\n| 3 | IP allowlist per tenant | `403 ip_not_allowed` |\n| 4 | Rate limit per tenant | `429 rate_limit_*` |\n| 5 | Scope per endpoint | `403 insufficient_scope` |\n\n## Response headers สำคัญ (ทุก response)\n\n| Header | ตัวอย่าง |\n|---|---|\n| `X-Gateway-Tenant-Id` | `wewasanad-nidtep` |\n| `X-Gateway-Auth-Mode` | `jwt` หรือ `legacy` |\n| `X-Gateway-Token-Expires-At` | `1787859307` (unix ts) |\n| `X-Gateway-Rate-Limit-Remaining` | `199` |\n| `X-Gateway-PII-Class` | `NONE` / `REDACTABLE` / `SENSITIVE` |\n| `X-Gateway-PII-Counts` | `PII_NID=1,PII_PHONE=1` |\n| `X-Gateway-Redaction-Layers` | `regex,heuristic-th` |\n| `X-Gateway-Compliance-Version` | `2026-05-29.3` |\n| `X-Gateway-Request-Id` | `chatcmpl-abc...` |\n| `X-Gateway-Audit-Url` | `/v1/audit/chatcmpl-abc...` |\n\n## Error response shape (OpenAI-compat)\n\n```json\n{\n  \"error\": {\n    \"message\": \"...\",\n    \"type\": \"invalid_request_error\",\n    \"code\": \"validation_error\",\n    \"param\": \"messages\"\n  }\n}\n```\n\nครอบ 11 types: `authentication_error`, `permission_error`, `not_found_error`,\n`invalid_request_error`, `payload_too_large_error`, `rate_limit_error`,\n`backend_error`, `timeout_error`, `compliance_failsafe_error`,\n`sensitive_routing_violation`, `internal_server_error`.\n\n## 📘 Integration Guide\n\nขอ `INTEGRATION_GUIDE.md` จาก operations — มี:\n- Quick start + sample code 5 ภาษา (Python / curl / Node / PHP / Go / **C#**)\n- §2 Auth — JWT lifecycle + rotation + ISO 27001 mapping\n- §7 PDPA + PII (educational, 9 sub-sections)\n- §8 Charts (PNG / SVG / Vega-Lite trade-offs)\n- §9 Error handling — taxonomy + retry policy + Polly pattern\n- §2.9 Wewasanad onboarding flow\n","contact":{"name":"AI Gateway TH Operations","email":"admin@kiatdamrong.shop"},"license":{"name":"Proprietary — B2B contract required"},"version":"0.12.0"},"servers":[{"url":"https://gateway.kiatdamrong.shop","description":"Production (CF Tunnel → DGX)"},{"url":"http://localhost:8000","description":"Local dev"}],"paths":{"/v1/audit/me":{"get":{"tags":["Audit & Transparency"],"summary":"ดู audit trail ของ tenant ของคุณ (self-serve)","description":"Returns this tenant's recent audit events (newest-first).\nUse to verify usage, debug failed requests, build cost dashboards.\n\nDefaults to last 24 hours, 100 events. PII never appears in the response\n(HARD RULE #3). Each event includes: ts, event, request_id, model, tier,\nelapsed_ms, tokens, pii_counts (counts only), status.\n\n**Time-window query params:**\n- `since` / `until` — unix timestamps (seconds since epoch). Default `since`\n  = now − 86400 (24h ago); `until` = now.\n- `event` — filter to `request`, `response`, or omit for both.\n- `limit` — 1..1000 (default 100).","operationId":"audit_for_me_v1_v1_audit_me_get","parameters":[{"name":"since","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Unix ts lower bound (default now-86400)","title":"Since"},"description":"Unix ts lower bound (default now-86400)"},{"name":"until","in":"query","required":false,"schema":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"Unix ts upper bound (default now)","title":"Until"},"description":"Unix ts upper bound (default now)"},{"name":"event","in":"query","required":false,"schema":{"anyOf":[{"type":"string","pattern":"^(request|response|error)$"},{"type":"null"}],"description":"Filter to one event kind","title":"Event"},"description":"Filter to one event kind"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Audit For Me V1 V1 Audit Me Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/audit/{request_id}":{"get":{"tags":["Audit & Transparency"],"summary":"ตรวจสอบ audit trail per-request","description":"คืน event ทั้งหมดของ request_id ที่ระบุ (scoped กับ tenant ที่เรียก).\n**ไม่มี raw message content หรือ raw PII ใน response นี้** (HARD RULE #3)","operationId":"audit_for_request_v1_audit__request_id__get","parameters":[{"name":"request_id","in":"path","required":true,"schema":{"type":"string","title":"Request Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Audit events for request_id","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Audit For Request V1 Audit  Request Id  Get"},"example":{"request_id":"chatcmpl-abc123","tenant":"demo-tenant","compliance_version_at_query":"2026-05-29.3","events":[{"event":"request","classification":"REDACTABLE","pii_counts":{"PII_NID":1,"PII_PHONE":1},"msg_chars":89,"model":"gateway-th"},{"event":"response","tier":"local","elapsed_ms":685,"tokens":{"total_tokens":42,"redacted_tokens":2}}]}}}},"404":{"description":"No events found for this request_id under your tenant"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/retention/rotate":{"post":{"tags":["Audit & Transparency"],"summary":"Rotate audit logs hot→cold + delete expired cold (admin)","description":"Admin-only. Moves records older than `GATEWAY_AUDIT_HOT_DAYS`\n(default 90) from `audit.jsonl` into gzipped daily files under cold dir.\nDeletes cold files older than `GATEWAY_AUDIT_COLD_DAYS` (default 365).\nIdempotent — safe to run on cron.","operationId":"retention_rotate_endpoint_v1_admin_retention_rotate_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Retention Rotate Endpoint V1 Admin Retention Rotate Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/retention/erase":{"post":{"tags":["Audit & Transparency"],"summary":"Erase all audit records for a tenant — PDPA §33 (admin)","description":"Admin-only. PDPA §33 right-to-be-forgotten implementation.\nRemoves every audit record matching `tenant_id` from hot AND cold storage.\nRecords the erasure itself in `operations.jsonl` with operator + reason\n(auditor proof). **Irreversible**.","operationId":"retention_erase_endpoint_v1_admin_retention_erase_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Body_retention_erase_endpoint_v1_admin_retention_erase_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Retention Erase Endpoint V1 Admin Retention Erase Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/retention/stats":{"get":{"tags":["Audit & Transparency"],"summary":"Audit storage stats (admin)","description":"Hot/cold record counts + sizes + retention policy.","operationId":"retention_stats_endpoint_v1_admin_retention_stats_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Retention Stats Endpoint V1 Admin Retention Stats Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/cost":{"get":{"tags":["Admin"],"summary":"Per-tenant usage aggregation (admin)","description":"Scans audit.jsonl for the last `hours` (default 24)\nand returns per-tenant request/response/error counts, model + tier\nbreakdown, token totals, and PII classification mix.\n\nThis is the DATA layer for cost reporting. Pricing model (→ THB\ninvoices) is deferred to Stage 2 (S3).","operationId":"cost_aggregate_v1_admin_cost_get","parameters":[{"name":"hours","in":"query","required":false,"schema":{"type":"integer","default":24,"title":"Hours"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Cost Aggregate V1 Admin Cost Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/flywheel/review":{"get":{"tags":["Admin · Flywheel"],"summary":"Rank user queries the KB answered weakly over a window","description":"Mines the audit log for `/v1/knowledge/query` calls\nwhose best hit's score is below `threshold`. Groups by (pack_id,\nnormalized_query) so repeated weak queries surface as one bucket. Ranked\nby `priority_score = count × (1 - avg_top_score)` so frequent + weak\nbeats rare + slightly weak.\n\nEach bucket includes `sample_request_ids` (up to 3) so you can pull the\nfull audit row via `/v1/admin/audit/{request_id}` to see who asked, what\nchunks were returned, and what the hybrid score breakdown was.\n\n**PII surface (audit §9 2026-06-05):** the linked `/v1/admin/audit/{id}`\nrecord contains the original user query, which in Thai medical / legal\ncontexts may include quasi-PII (e.g. specific health-condition phrasing).\nThis endpoint requires admin scope — treat the admin token as\nPII-sensitive and rotate via `/v1/admin/providers/keys/...` if exposed.\n\nFilters: `pack_id` restricts to one pack; `min_count` drops singletons.\n\nNote: only audits emitted AFTER the flywheel enrichment ship date\n(2026-06-03) carry the score/query fields. Older rows are silently\nignored — the count is over enriched rows only.","operationId":"flywheel_review_v1_admin_flywheel_review_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","description":"Time window: 1h|6h|24h|7d|14d|30d or raw seconds","default":"7d","title":"Window"},"description":"Time window: 1h|6h|24h|7d|14d|30d or raw seconds"},{"name":"threshold","in":"query","required":false,"schema":{"type":"number","maximum":1.0,"minimum":0.0,"description":"Only return buckets with avg_top_score < threshold","default":0.45,"title":"Threshold"},"description":"Only return buckets with avg_top_score < threshold"},{"name":"pack_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional filter to a single pack","title":"Pack Id"},"description":"Optional filter to a single pack"},{"name":"min_count","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"description":"Drop buckets seen fewer than N times in window","default":1,"title":"Min Count"},"description":"Drop buckets seen fewer than N times in window"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":500,"minimum":1,"default":50,"title":"Limit"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Flywheel Review V1 Admin Flywheel Review Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/flywheel/summary":{"get":{"tags":["Admin · Flywheel"],"summary":"One-shot KPI for KB query health (count, avg top score)","description":"Returns aggregate metrics over the window: how many\nflywheel-eligible queries fired, how many packs were touched, the\naverage top score, and the zero-hit rate. Use to tell whether the KB\nis \"answering well on average\" before drilling into review buckets.","operationId":"flywheel_summary_v1_admin_flywheel_summary_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Window"}},{"name":"pack_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Flywheel Summary V1 Admin Flywheel Summary Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/flywheel/fill-gap":{"post":{"tags":["Admin · Flywheel"],"summary":"เติมความรู้จาก gap: ค้นเว็บ → ร่าง draft รอรีวิว (ครบ loop)","description":"**Knowledge flywheel — ปิดวงจร.** รับ weak query จาก\n`/v1/admin/flywheel/review` → web_search (หรือ URLs ที่ระบุ) → ร่าง\ndraft ต่อ source ผ่าน writer → คืน draft ids สำหรับ review/approve\n(ของเดิม: GET/POST /v1/admin/packs/{id}/drafts/...). ยัง anti-fabrication:\nไม่มีอะไรเข้า pack จนกว่า curator จะ approve.","operationId":"fill_gap_v1_admin_flywheel_fill_gap_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FillGapBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Fill Gap V1 Admin Flywheel Fill Gap Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/flywheel/fill-gap-from-research":{"post":{"tags":["Admin · Flywheel"],"summary":"ดูด flywheel signals จาก deep-research job → ร่าง drafts ทุกแพ็คในรวดเดียว","description":"H.2 wiring (2026-06-14). รับ `job_id` ของ deep research\nที่ done แล้ว → อ่าน `flywheel_signals` ใน job.result (weak pack hits) →\ngroup by pack → สำหรับแต่ละกลุ่ม เรียก fill-gap ตัวเดิม (web_search → drafts).\n\nใช้ทำอะไร: ลูกค้ารัน deep research 1 รอบ = อาจสร้าง weak signals หลายสิบตัว.\nปกติ curator จะรอเก็บใน /flywheel/review ทีละช่วง ก่อนกด fill-gap ทีละ pack.\nendpoint นี้รวบงานให้ — รัน 1 ครั้ง = drafts ครบทุก pack ที่อ่อนใน research นั้น","operationId":"fill_gap_from_research_v1_admin_flywheel_fill_gap_from_research_post","parameters":[{"name":"job_id","in":"query","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"max_sources_per_query","in":"query","required":false,"schema":{"type":"integer","default":2,"title":"Max Sources Per Query"}},{"name":"max_queries_per_pack","in":"query","required":false,"schema":{"type":"integer","default":3,"title":"Max Queries Per Pack"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Fill Gap From Research V1 Admin Flywheel Fill Gap From Research Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/quality":{"get":{"tags":["Admin · Flywheel"],"summary":"Ranked pack-quality dashboard: usage × hit-score × freshness","description":"H.2 Step 7 (2026-06-14). Combines 4 signals into one\nranked list:\n1. Usage frequency — pack queries in window\n2. Hit quality — avg top_score across queries\n3. Freshness — pack_freshness().age_days vs freshness_days\n4. Deep-research weighting — queries from deep_research product count 5×\n   (more thorough usage → richer signal)\n\nใช้แทน curator: 'top 5 packs ที่อ่อนสุด + คุ้มดูแลก่อน' ลำดับงาน Kiat\nกำหนดได้ก่อนเลย","operationId":"pack_quality_dashboard_v1_admin_packs_quality_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Window"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"minimum":1,"default":20,"title":"Limit"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Pack Quality Dashboard V1 Admin Packs Quality Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/insights/latency":{"get":{"tags":["Admin · Insights"],"summary":"Latency percentiles (p50/p95/p99) over a sliding window","description":"Returns request count, error count, and p50/p95/p99\nlatency aggregated by hour bucket. Optional filters:\n\n- `endpoint` — e.g. `smart:content_polish`\n- `tier` — `standard` / `premium` / `frontier` / `auto`\n- `tenant` — restrict to one tenant\n\nThe response includes `by_hour` (time series) and `overall` (window\ntotals). p95/p99 across multi-bucket hours are weighted-averaged from\nhour-bucket aggregates — useful for trend spotting, not exact SLA math.","operationId":"latency_insights_v1_admin_insights_latency_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","description":"Time window: 1h|6h|24h|7d|14d or raw seconds","default":"24h","title":"Window"},"description":"Time window: 1h|6h|24h|7d|14d or raw seconds"},{"name":"endpoint","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endpoint"}},{"name":"tier","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier"}},{"name":"tenant","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tenant"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Latency Insights V1 Admin Insights Latency Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/insights/tier-mix":{"get":{"tags":["Admin · Insights"],"summary":"Request count and token usage grouped by tier","description":"Answers: \"What tier mix is a tenant actually using?\"\nReturns per-tier request count, error count, and token totals (in/out)\nacross the window. Use to verify a tenant's `default_tier` setting is\nproducing the expected behavior.","operationId":"tier_mix_insights_v1_admin_insights_tier_mix_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"7d","title":"Window"}},{"name":"tenant","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tenant"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Tier Mix Insights V1 Admin Insights Tier Mix Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/insights/errors":{"get":{"tags":["Admin · Insights"],"summary":"Top error fingerprints over the window","description":"Returns the most-frequent error fingerprints (error\nclass + first 32 chars of brief) with counts. For at-a-glance triage:\n\"Are we seeing a new failure mode?\"","operationId":"errors_insights_v1_admin_insights_errors_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"24h","title":"Window"}},{"name":"endpoint","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Endpoint"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200,"minimum":1,"default":20,"title":"Limit"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Errors Insights V1 Admin Insights Errors Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/insights/rollup":{"post":{"tags":["Admin · Insights"],"summary":"Force an immediate rollup (idempotent)","description":"Manual trigger for the rollup job. Useful when you've\njust generated test traffic and want to query insights without waiting\nfor the next 5-min systemd tick. Returns the rollup stats dict.","operationId":"trigger_rollup_v1_admin_insights_rollup_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer"},"title":"Response Trigger Rollup V1 Admin Insights Rollup Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/inflight":{"get":{"tags":["Admin"],"summary":"List in-flight smart-query slots for a tenant (optionally per-product)","description":"Phase G: ``product`` query param filters to the per-product\ninflight SET (``tenant:<id>:product:<product>:inflight``). Omit it\nto see the tenant-wide overall view.","operationId":"list_inflight_v1_admin_tenants__tenant_id__inflight_get","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"product","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InflightList"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/inflight/stats":{"get":{"tags":["Admin"],"summary":"Aggregate stats for a tenant's in-flight slots","operationId":"inflight_stats_v1_admin_tenants__tenant_id__inflight_stats_get","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InflightStats"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/prefix-stats":{"get":{"tags":["Admin"],"summary":"Per-(model, window) KV-cache hit-ratio for a tenant","description":"Reports how often this tenant's incoming requests share an N-character\nprefix with a previous request to the same model within 5 minutes.\n\nInterpretation guide:\n  - hit_ratio @ 500 chars   ≈ system-prompt reuse rate\n  - hit_ratio @ 2000 chars  ≈ chat-history reuse rate\n  - hit_ratio @ 4000 chars  ≈ full multi-turn context reuse\n\nHigh values (>50%) at large windows indicate the backend is reusing\nits KV cache for this tenant's traffic — a direct throughput win.","operationId":"prefix_stats_v1_admin_tenants__tenant_id__prefix_stats_get","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrefixStats"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/cancel-all":{"post":{"tags":["Admin"],"summary":"Mark every in-flight slot FAILED for a tenant","description":"Releases pub/sub waiters and transitions every INFLIGHT slot to FAILED\nso duplicates can re-claim and run fresh. Safe to call repeatedly.\n\nUse when:\n  - A customer's traffic is stuck (e.g. backend hang we already fixed)\n  - You need to clear a noisy tenant before a deploy\n  - Per-tenant circuit-breaker manual trip\n\nDoes NOT cancel the actual LLM calls already in progress on the worker\nside — those run to completion in the background. The customer's\nclient just gets a freed-up retry window via Lua's FAILED→claimable\ntransition.","operationId":"cancel_all_v1_admin_tenants__tenant_id__cancel_all_post","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"product","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CancelResult"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/products":{"get":{"tags":["Admin"],"summary":"Phase G: list products that currently hold inflight slots for this tenant","description":"**Per-product axis** — shows which of a multi-product\ntenant's product labels currently have inflight smart-query slots.\n\nUse cases:\n- \"Is the deep_research load on this tenant blocking their chat product?\"\n- Quick health check before issuing a per-product cancel-all\n- Mixed with `GET /v1/admin/products` (audit-log-based) for traffic share\n  vs current load.","operationId":"list_tenant_products_v1_admin_tenants__tenant_id__products_get","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantProductsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/pii/assist":{"get":{"tags":["Admin"],"summary":"PIIAssistBot stats: cache hit-rate + FP/FN candidates","description":"Surfaces three things to reduce the human burden of maintaining\nclassify.py rules:\n\n- **Counters**: prefilter_hit / cache_hit / cache_miss / fp_candidate /\n  validator_leak — running totals since process start.\n- **FP candidates**: short messages classified REDACTABLE on a single\n  non-strong category (PERSON/ADDRESS). Likely over-protection that\n  would benefit from a stop-list addition.\n- **FN candidates**: messages where the validator HARD-RULE-1 caught a\n  leftover placeholder. Indicates either model hallucination of fake\n  placeholders OR a real PII pattern slipping through to the model.\n- **Prefilter samples**: recent text that was fast-pathed as NONE.\n\nReset stats only via process restart for now (low-volume admin task).","operationId":"pii_assist_stats_v1_admin_pii_assist_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Pii Assist Stats V1 Admin Pii Assist Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/providers/keys":{"get":{"tags":["Admin"],"summary":"List upstream provider keys (last4 only)","description":"Admin-facing list of upstream API keys currently in use. Returns\nlast4 + length + has_key for each provider — never the full value.","operationId":"list_provider_keys_v1_admin_providers_keys_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListKeysOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/providers/keys/{provider}":{"post":{"tags":["Admin"],"summary":"Rotate an upstream provider key (validates against provider)","description":"Atomically validate + swap an upstream provider API key.\n\nFlow:\n  1. Reject unknown provider (404)\n  2. Reject empty/whitespace key (400)\n  3. (default) Live-call the provider with the new key — abort on\n     non-2xx (422)\n  4. Atomically write secrets.env + update in-memory state\n  5. Return last4 + a reminder to revoke the OLD key at the\n     provider's console (leaked old keys still work until then)","operationId":"set_provider_key_v1_admin_providers_keys__provider__post","parameters":[{"name":"provider","in":"path","required":true,"schema":{"type":"string","title":"Provider"}},{"name":"skip_validate","in":"query","required":false,"schema":{"type":"boolean","description":"Skip the live validate-against-provider check. Useful when the provider is down OR the admin has already verified the key in the provider's console. NOT recommended in normal operation.","default":false,"title":"Skip Validate"},"description":"Skip the live validate-against-provider check. Useful when the provider is down OR the admin has already verified the key in the provider's console. NOT recommended in normal operation."},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetKeyIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetKeyOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/pool/status":{"get":{"tags":["Admin · Model Pool"],"summary":"Per-model pool snapshot (in_flight, waiting, p50/p95 wait + hold)","description":"Returns the live state of every model pool that has\nseen at least one acquisition since startup. Snapshot includes the\nconfigured limit + queue size, the in-flight + waiting counters, a\nper-tenant in-flight breakdown (useful when a tenant looks noisy), and\npercentile latency over the recent sample window.","operationId":"pool_status_v1_admin_pool_status_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Pool Status V1 Admin Pool Status Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/pool/breakers":{"get":{"tags":["Admin · Model Pool"],"summary":"Per-model circuit-breaker snapshot","operationId":"breaker_status_v1_admin_pool_breakers_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Breaker Status V1 Admin Pool Breakers Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/pool/history":{"get":{"tags":["Admin · Model Pool"],"summary":"Recent limit changes (operator + adaptive)","operationId":"pool_history_v1_admin_pool_history_get","parameters":[{"name":"model_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Id"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":1000,"minimum":1,"default":100,"title":"Limit"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Pool History V1 Admin Pool History Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/pool/adaptive":{"get":{"tags":["Admin · Model Pool"],"summary":"Adaptive controller stats (ticks, changes, last decisions)","operationId":"adaptive_status_v1_admin_pool_adaptive_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Adaptive Status V1 Admin Pool Adaptive Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/pool/{model_id}/limit":{"post":{"tags":["Admin · Model Pool"],"summary":"Override the pool's limit and/or queue_size (persisted)","description":"Persists the override in sqlite so it survives a\ndeploy. Also appends a history entry tagged with `actor`. Pass at\nleast one of `limit` or `queue_size`.","operationId":"set_pool_limit_v1_admin_pool__model_id__limit_post","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_LimitBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Set Pool Limit V1 Admin Pool  Model Id  Limit Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/pool/{model_id}/breaker/force-close":{"post":{"tags":["Admin · Model Pool"],"summary":"Force the circuit closed (resets counters + backoff)","operationId":"breaker_force_close_v1_admin_pool__model_id__breaker_force_close_post","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Breaker Force Close V1 Admin Pool  Model Id  Breaker Force Close Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/pool/{model_id}/breaker/force-open":{"post":{"tags":["Admin · Model Pool"],"summary":"Force the circuit open for at least `cooldown_s` seconds","operationId":"breaker_force_open_v1_admin_pool__model_id__breaker_force_open_post","parameters":[{"name":"model_id","in":"path","required":true,"schema":{"type":"string","title":"Model Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/_BreakerOpenBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Breaker Force Open V1 Admin Pool  Model Id  Breaker Force Open Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/products":{"get":{"tags":["Admin · Products"],"summary":"Per-product summary across audit window (H.2 Step 6)","description":"**Per-product axis** — aggregates the audit JSONL by\nthe `product` field added in Sprint H.2 (2026-06-14). For a Wewasanad\npilot tenant testing many products under one token, this answers:\n\n- how much traffic comes from each product\n- which product produces flywheel signals (typically deep_research)\n- ratio of chat vs research vs OCR vs knowledge-query\n\nDefault window 24h. Filter by tenant if running multi-tenant.","operationId":"list_products_v1_admin_products_get","parameters":[{"name":"window","in":"query","required":false,"schema":{"type":"string","default":"24h","title":"Window"}},{"name":"tenant_filter","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"if set, only audit events for this tenant","title":"Tenant Filter"},"description":"if set, only audit events for this tenant"},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Products V1 Admin Products Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/keys":{"post":{"tags":["Admin · Sub-keys"],"summary":"Issue a sub-key (JWT) for this tenant","description":"Mints a new JWT scoped to this tenant. Returns the\n**raw token ONCE** — store it client-side; the gateway only keeps meta\n(jti, label, scopes, product_id, issued_at) for admin listings.\n\nIf `product_id` is set, every request using this token is auto-tagged\nwith that product in audit + Prometheus — no X-Product-Id header\nrequired on the client side.","operationId":"issue_subkey_v1_admin_tenants__tenant_id__keys_post","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueBody"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin · Sub-keys"],"summary":"List registered sub-keys for a tenant","operationId":"list_subkeys_v1_admin_tenants__tenant_id__keys_get","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KeyListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/keys/{jti}":{"delete":{"tags":["Admin · Sub-keys"],"summary":"Revoke a sub-key by jti (adds to gateway-wide deny-list)","operationId":"revoke_subkey_v1_admin_tenants__tenant_id__keys__jti__delete","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"jti","in":"path","required":true,"schema":{"type":"string","title":"Jti"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/sla-config":{"get":{"tags":["Admin · SLA"],"summary":"Read SLA credit policy for a tenant","operationId":"get_sla_config_v1_admin_tenants__tenant_id__sla_config_get","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlaConfigResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Admin · SLA"],"summary":"Enable / disable SLA credit policy for a tenant","description":"Default for every tenant is **OFF** — the auto-credit\ncalculator skips them entirely. This is correct for:\n\n- **On-premise appliance customers** (no credit contract — they own the\n  hardware so latency/availability is partly their responsibility)\n- **Pre-contract pilots** (we haven't agreed credit terms yet)\n- **Internal / demo tenants**\n\nToggle to **ON** when a customer signs a SaaS contract with explicit\ncredit terms (see `docs/SLA_FRAMEWORK.md`).\n\nWrites back to `~/.config/ai-gateway/tenants.yaml` and the registry\nhot-reloads on file mtime change — no service restart required.","operationId":"set_sla_config_v1_admin_tenants__tenant_id__sla_config_put","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlaConfigUpdate"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlaConfigResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/sla-config":{"get":{"tags":["Admin · SLA"],"summary":"List SLA credit policy for ALL tenants","operationId":"list_sla_configs_v1_admin_sla_config_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Sla Configs V1 Admin Sla Config Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/bots":{"get":{"tags":["Admin · Bots"],"summary":"List registered bots and runtime status","operationId":"list_bots_v1_admin_bots_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Bots V1 Admin Bots Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/bots/kill-switch":{"get":{"tags":["Admin · Bots"],"summary":"Current state of every kill switch","operationId":"kill_switch_state_v1_admin_bots_kill_switch_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Kill Switch State V1 Admin Bots Kill Switch Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/bots/{name}/disable":{"post":{"tags":["Admin · Bots"],"summary":"Globally disable a bot (no per-tenant override)","operationId":"disable_bot_v1_admin_bots__name__disable_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Disable Bot V1 Admin Bots  Name  Disable Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/bots/{name}/enable":{"post":{"tags":["Admin · Bots"],"summary":"Globally re-enable a bot","operationId":"enable_bot_v1_admin_bots__name__enable_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Enable Bot V1 Admin Bots  Name  Enable Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/bots/kill-switch/all-off":{"post":{"tags":["Admin · Bots"],"summary":"EMERGENCY — disable all bots system-wide","operationId":"all_off_v1_admin_bots_kill_switch_all_off_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response All Off V1 Admin Bots Kill Switch All Off Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/bots/kill-switch/all-on":{"post":{"tags":["Admin · Bots"],"summary":"Recover from all-off","operationId":"all_on_v1_admin_bots_kill_switch_all_on_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response All On V1 Admin Bots Kill Switch All On Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/model-guard":{"get":{"tags":["Admin · Models"],"summary":"OOM guard snapshot — usable VRAM + per-model class + fallback map","operationId":"model_guard_snapshot_v1_admin_model_guard_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Model Guard Snapshot V1 Admin Model Guard Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/bots/ledger":{"get":{"tags":["Admin · Bots"],"summary":"Recent BOT action ledger (per-bot or global)","operationId":"ledger_v1_admin_bots_ledger_get","parameters":[{"name":"bot_name","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Bot Name"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Ledger V1 Admin Bots Ledger Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/orchestration":{"get":{"tags":["Admin"],"summary":"Smart Model Orchestration snapshot","description":"Live state of the orchestrator:\n\n- ``hot_now``: models with traffic in the last 10 min (sorted by RPS)\n- ``warming``: models the bot is actively preloading RIGHT NOW\n- ``loaded``: bare-tag names from Ollama ``/api/ps``\n- ``eviction_candidates``: loaded but idle for >1 hour (advisory)\n- ``recent_decisions``: capped trail of bot actions (preload / skip / evict_suggest)\n- ``policy``: tuning knobs in effect\n\nAdmin scope. No rate-limit cost (read-only telemetry).","operationId":"admin_orchestration_v1_admin_orchestration_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Admin Orchestration V1 Admin Orchestration Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs":{"post":{"tags":["Admin · Packs"],"summary":"Create a new (empty) pack","operationId":"create_pack_v1_admin_packs_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Pack V1 Admin Packs Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/sources":{"post":{"tags":["Admin · Packs"],"summary":"Upload one source chunk file to an existing pack","description":"Validates the chunk against the style guide (frontmatter required, body length, TL;DR recommended). Returns 400 on validation failure. Does NOT auto-ingest — call POST /ingest explicitly after a batch.","operationId":"upload_source_v1_admin_packs__pack_id__sources_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_source_v1_admin_packs__pack_id__sources_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Upload Source V1 Admin Packs  Pack Id  Sources Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/drafts":{"get":{"tags":["Admin · Packs"],"summary":"List pending draft chunks","operationId":"list_drafts_v1_admin_packs__pack_id__drafts_get","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Drafts V1 Admin Packs  Pack Id  Drafts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/drafts/{filename}":{"get":{"tags":["Admin · Packs"],"summary":"Read a single draft (full content + validation)","operationId":"read_draft_v1_admin_packs__pack_id__drafts__filename__get","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Read Draft V1 Admin Packs  Pack Id  Drafts  Filename  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/drafts/{filename}/approve":{"post":{"tags":["Admin · Packs"],"summary":"Approve a draft → move to sources/ (live)","operationId":"approve_draft_v1_admin_packs__pack_id__drafts__filename__approve_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Approve Draft V1 Admin Packs  Pack Id  Drafts  Filename  Approve Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/drafts/{filename}/reject":{"post":{"tags":["Admin · Packs"],"summary":"Reject a draft → delete from drafts/","operationId":"reject_draft_v1_admin_packs__pack_id__drafts__filename__reject_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"filename","in":"path","required":true,"schema":{"type":"string","title":"Filename"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Reject Draft V1 Admin Packs  Pack Id  Drafts  Filename  Reject Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/ingest":{"post":{"tags":["Admin · Packs"],"summary":"Regenerate chunks.json from sources/ (call after adding chunks)","description":"Re-reads all sources/*.md, runs the existing ingest pipeline, and writes chunks.json. Embeddings are generated for new chunks and reused for unchanged ones. Returns count summary.","operationId":"ingest_pack_v1_admin_packs__pack_id__ingest_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Ingest Pack V1 Admin Packs  Pack Id  Ingest Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/version":{"put":{"tags":["Admin · Packs"],"summary":"Bump pack version (metadata only)","operationId":"bump_version_v1_admin_packs__pack_id__version_put","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VersionIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Bump Version V1 Admin Packs  Pack Id  Version Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/access":{"post":{"tags":["Admin · Packs"],"summary":"Grant tenants access to a private pack","description":"Adds tenant IDs to the pack's `entitlement.default_tenants` list. Use for private packs (tenant-specific content). Public packs (entitlement.subscription_required=False) don't need this.","operationId":"grant_access_v1_admin_packs__pack_id__access_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PackAccessIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Grant Access V1 Admin Packs  Pack Id  Access Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/packs/{pack_id}/retire":{"post":{"tags":["Admin · Packs"],"summary":"Soft-delete a pack (move to retired/)","description":"Renames packs/<id>/ to packs/.retired/<id>.<timestamp>/ so list_packs() skips it. Restorable by manual mv on the server.","operationId":"retire_pack_v1_admin_packs__pack_id__retire_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Retire Pack V1 Admin Packs  Pack Id  Retire Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/prompts":{"get":{"tags":["Admin · Prompts"],"summary":"List hot-editable prompts","description":"Returns one summary row per registered prompt: name,\ndefault char-length, active version (0 if no overrides), latest update\nmetadata. To see the actual prompt body, fetch the per-name detail.","operationId":"list_prompts_v1_admin_prompts_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Prompts V1 Admin Prompts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/prompts/{name}":{"get":{"tags":["Admin · Prompts"],"summary":"Get a prompt's default + active value + version history","operationId":"get_prompt_v1_admin_prompts__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Prompt V1 Admin Prompts  Name  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Admin · Prompts"],"summary":"Overwrite a prompt (takes effect immediately)","description":"Writes a new version to the registry. Next request\non a wizard / smart route using this prompt uses the new value. The\nprevious version stays in history for one-call rollback. Mutation is\naudited via prompts_audit.jsonl.\n\nAudit fields recorded: ts, event=set, name, version, operator,\nnote, value_chars. The prompt BODY is NOT logged (per HARD RULE — same\npolicy as the regular audit log).","operationId":"put_prompt_v1_admin_prompts__name__put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptSetIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Put Prompt V1 Admin Prompts  Name  Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/prompts/{name}/shadow":{"put":{"tags":["Admin · Prompts"],"summary":"Register a shadow candidate for A/B comparison","description":"Sets a shadow prompt that will be run in parallel\n(background) on `sample_pct` of customer requests. Customer-visible\nresponse is always the ACTIVE prompt's result; the shadow runs in a\ndaemon thread AFTER the response goes out, then logs both scores to a\ncomparisons file.\n\nOnly ONE shadow per prompt name at a time; new shadow overwrites the\nprevious slot.\n\nOnce you have enough samples (see GET .../shadow/comparison), promote\nby `PUT /v1/admin/prompts/{name}` with the shadow's value, then clear\nthe shadow with DELETE.","operationId":"put_shadow_v1_admin_prompts__name__shadow_put","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShadowSetIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Put Shadow V1 Admin Prompts  Name  Shadow Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin · Prompts"],"summary":"Read the current shadow slot (if any)","operationId":"get_shadow_v1_admin_prompts__name__shadow_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Shadow V1 Admin Prompts  Name  Shadow Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin · Prompts"],"summary":"Clear the shadow slot","operationId":"delete_shadow_v1_admin_prompts__name__shadow_delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Shadow V1 Admin Prompts  Name  Shadow Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/prompts/{name}/shadow/comparison":{"get":{"tags":["Admin · Prompts"],"summary":"Aggregate shadow A/B results over the last `window_s`","operationId":"shadow_comparison_v1_admin_prompts__name__shadow_comparison_get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"window_s","in":"query","required":false,"schema":{"type":"integer","default":604800,"title":"Window S"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Shadow Comparison V1 Admin Prompts  Name  Shadow Comparison Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/prompts/{name}/rollback":{"post":{"tags":["Admin · Prompts"],"summary":"Drop the latest version (1-call revert)","description":"Removes the most-recent override. The previous\nversion (if any) becomes active. If no overrides exist, returns\n404 with `nothing_to_rollback`.","operationId":"rollback_prompt_v1_admin_prompts__name__rollback_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Rollback Prompt V1 Admin Prompts  Name  Rollback Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/prompts-baseline":{"get":{"tags":["Admin · Prompts"],"summary":"Baseline metadata (when captured, by whom, which prompts)","operationId":"get_baseline_v1_admin_prompts_baseline_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Baseline V1 Admin Prompts Baseline Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/prompts-baseline/snapshot":{"post":{"tags":["Admin · Prompts"],"summary":"Freeze current ACTIVE prompts as the restore baseline","description":"Captures the active value of every registered prompt\ninto the baseline file. Run this when the prompt set is in a known-good\nstate (e.g. before handing the demo to testers). Overwrites the\nprevious baseline.","operationId":"snapshot_baseline_v1_admin_prompts_baseline_snapshot_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Snapshot Baseline V1 Admin Prompts Baseline Snapshot Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/prompts-baseline/restore":{"post":{"tags":["Admin · Prompts"],"summary":"Restore prompt(s) to the captured baseline","description":"One call undoes ANY number of demo-time edits.\nRestores write through the normal versioning path so history and the\naudit trail are preserved (a restore itself can be rolled back).\nPrompts already matching the baseline are skipped.","operationId":"restore_baseline_v1_admin_prompts_baseline_restore_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/RestoreBaselineBody"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Restore Baseline V1 Admin Prompts Baseline Restore Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/corpus":{"post":{"tags":["Corpus"],"summary":"Create a project corpus","operationId":"create_corpus_v1_corpus_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCorpusBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Corpus V1 Corpus Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Corpus"],"summary":"List my corpora","operationId":"list_corpora_v1_corpus_get","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Corpora V1 Corpus Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/corpus/{corpus_id}":{"get":{"tags":["Corpus"],"summary":"Corpus info + PDPA profile","operationId":"get_corpus_v1_corpus__corpus_id__get","parameters":[{"name":"corpus_id","in":"path","required":true,"schema":{"type":"string","title":"Corpus Id"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Corpus V1 Corpus  Corpus Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Corpus"],"summary":"ลบ corpus + chunks ทั้งหมด (data lifecycle)","operationId":"delete_corpus_v1_corpus__corpus_id__delete","parameters":[{"name":"corpus_id","in":"path","required":true,"schema":{"type":"string","title":"Corpus Id"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Corpus V1 Corpus  Corpus Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/corpus/{corpus_id}/documents":{"post":{"tags":["Corpus"],"summary":"Upload a document (PDF/DOCX/TXT, no page cap)","operationId":"upload_document_v1_corpus__corpus_id__documents_post","parameters":[{"name":"corpus_id","in":"path","required":true,"schema":{"type":"string","title":"Corpus Id"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_document_v1_corpus__corpus_id__documents_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Upload Document V1 Corpus  Corpus Id  Documents Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/corpus/{corpus_id}/query":{"post":{"tags":["Corpus"],"summary":"Hybrid retrieval (explicit tool-call — no silent RAG)","operationId":"query_corpus_v1_corpus__corpus_id__query_post","parameters":[{"name":"corpus_id","in":"path","required":true,"schema":{"type":"string","title":"Corpus Id"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/QueryBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Query Corpus V1 Corpus  Corpus Id  Query Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/longform":{"post":{"tags":["Longform"],"summary":"Map-reduce summarize/compose over a whole corpus (resumable, overnight-safe)","operationId":"start_longform_v1_longform_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LongformBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Start Longform V1 Longform Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/longform/schedules":{"post":{"tags":["Longform"],"summary":"ตั้งเวลารัน longform ประจำ (ทุก N ชั่วโมง)","operationId":"create_schedule_v1_longform_schedules_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScheduleBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Create Schedule V1 Longform Schedules Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Longform"],"summary":"ดู schedule ทั้งหมดของฉัน","operationId":"list_schedules_v1_longform_schedules_get","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Schedules V1 Longform Schedules Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/longform/schedules/{sid}":{"delete":{"tags":["Longform"],"summary":"ยกเลิก schedule","operationId":"delete_schedule_v1_longform_schedules__sid__delete","parameters":[{"name":"sid","in":"path","required":true,"schema":{"type":"string","title":"Sid"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Schedule V1 Longform Schedules  Sid  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/export":{"post":{"tags":["Export"],"summary":"Markdown → DOCX / PPTX / MD (ฟอนต์ไทย A4)","operationId":"export_doc_v1_export_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExportBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/jobs/{job_id}/export":{"get":{"tags":["Export"],"summary":"Export a DONE longform job's markdown result","operationId":"export_job_v1_jobs__job_id__export_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"docx","title":"Format"}},{"name":"title","in":"query","required":false,"schema":{"type":"string","default":"รายงาน","title":"Title"}},{"name":"author","in":"query","required":false,"schema":{"type":"string","default":"","title":"Author"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/research":{"post":{"tags":["Research"],"summary":"Deep Research — AI ค้น→อ่าน→ค้นต่อ→cross-check →ตอบพร้อม citations (multi-hop)","operationId":"deep_research_v1_research_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResearchBody"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Deep Research V1 Research Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/research/deep":{"post":{"tags":["Research"],"summary":"Deep Research L2 (async): plan → sub-research per section → synthesize","description":"L2 รัน async ผ่าน /v1/jobs infra. คืน {job_id} ทันที. Planner แตกคำถาม → 3-7 บท → research แต่ละบทผ่าน L1 loop → synthesizer รวมเป็นรายงาน markdown มีโครงสร้าง + citations. Poll progress: GET /v1/jobs/{id} (progress field มี stage + sections_done/total).","operationId":"deep_research_async_v1_research_deep_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeepResearchBody"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Deep Research Async V1 Research Deep Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/research/deep/{job_id}/stream":{"get":{"tags":["Research"],"summary":"SSE stream of deep-research progress (H.1.1, 2026-06-14)","description":"Server-Sent Events stream for a running deep-research\njob. Emits `event: ready` once, then `event: progress` on every progress\nchange (stage transition or sections_done bump), then `event: done`\n(with summary stats) or `event: failed` once at terminal state.\n\nUse this instead of polling `/v1/jobs/{job_id}` if you want a live UI\nwithout delaying for a poll interval. CF Tunnel tolerates SSE up to 100s\nbetween events; we keep the tick at 1s so that's comfortable.","operationId":"deep_research_stream_v1_research_deep__job_id__stream_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/research/whitelist":{"get":{"tags":["Admin · Research"],"summary":"List per-domain authoritative source whitelist","operationId":"get_whitelist_v1_admin_research_whitelist_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Whitelist V1 Admin Research Whitelist Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/research/whitelist/{domain}":{"put":{"tags":["Admin · Research"],"summary":"Override / extend the source whitelist for a domain (runtime)","description":"Effective until process restart. For permanent change edit SOURCE_WHITELIST in `gateway.research_agent`.","operationId":"put_whitelist_v1_admin_research_whitelist__domain__put","parameters":[{"name":"domain","in":"path","required":true,"schema":{"type":"string","title":"Domain"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WhitelistIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Put Whitelist V1 Admin Research Whitelist  Domain  Put"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/research":{"post":{"tags":["Admin · Research"],"summary":"Start a research job for a pack (planner runs first)","operationId":"start_research_v1_admin_research_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartResearchIn"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Start Research V1 Admin Research Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Admin · Research"],"summary":"List recent research jobs","operationId":"list_research_v1_admin_research_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":30,"title":"Limit"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Research V1 Admin Research Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/research/{job_id}":{"get":{"tags":["Admin · Research"],"summary":"Get one job's state + progress","operationId":"get_research_v1_admin_research__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Research V1 Admin Research  Job Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/models":{"get":{"tags":["Catalog"],"summary":"รายชื่อ model ที่ใช้ได้","description":"คืน catalog ของ model ทั้งหมดที่ tenant สามารถใช้ได้ พร้อม metadata ของแต่ละ tier.\n\n**Tier:** `local` (Spark TH, ฟรี, in-country), `cloud` (Ollama Cloud, ข้อมูลออกนอก),\n`frontier` (Anthropic/Google, per-token, ข้อมูลออกนอก).\n\n**Smart aliases:** `gateway-th` (auto-route Thai → local-fast), `gateway-embed` (nomic 768-dim).","operationId":"list_models_v1_models_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Models V1 Models Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/embeddings":{"post":{"tags":["Embeddings"],"summary":"OpenAI-compat embeddings (in-country)","description":"**OpenAI-compatible embeddings.** Default `gateway-embed` =\n`nomic-embed-text` บน Spark (768-dim, ฟรี, in-country). ใช้กับ vector DB\n(Qdrant/pgvector/Chroma) ของลูกค้าได้ทันที. PII note: ลูกค้าควร redact\nก่อนส่งมา embed (เรา classify + audit แต่ไม่ redact เพราะจะทำลาย\nsemantic similarity).","operationId":"embeddings_endpoint_v1_embeddings_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmbeddingRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Embeddings Endpoint V1 Embeddings Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/knowledge/packs":{"get":{"tags":["Knowledge"],"summary":"รายชื่อ knowledge pack ทั้งหมด","description":"คืน list ของ knowledge pack + metadata + chunk count. ไม่กิน rate-limit budget.","operationId":"list_knowledge_packs_v1_knowledge_packs_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Knowledge Packs V1 Knowledge Packs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/knowledge/query":{"post":{"tags":["Knowledge"],"summary":"ค้นหา chunk จาก knowledge pack (hybrid keyword + vector)","description":"ค้นหา chunk ที่เกี่ยวข้องกับ `query` จาก pack ที่ระบุ.\nคืน chunks พร้อม score (0..1), citations, audience_levels.","operationId":"query_knowledge_v1_knowledge_query_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeQueryRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Query Knowledge V1 Knowledge Query Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/chat/completions":{"post":{"tags":["Chat & Completions"],"summary":"OpenAI-compat chat completion (streaming + tools + JSON mode)","description":"**OpenAI-compatible chat completions endpoint.**\n\nทำงานเหมือน OpenAI API ทุกประการ ลูกค้าใช้ `openai` SDK ของภาษาใดก็ได้:\n\n```python\nclient.chat.completions.create(model=\"gateway-th\", messages=[...])\n```\n\n## Features รองรับ\n\n- ✅ Streaming SSE (`stream=true`)\n  - `NONE` classification → pass-through real-time chunks\n  - `REDACTABLE` → buffer + detokenize + emit fake chunks (spec §5.3)\n- ✅ Function calling (`tools`, `tool_choice`)\n- ✅ JSON mode (`response_format={\"type\": \"json_object\"}`)\n- ✅ Structured content (`content: list[dict]`) — vision, cache_control, tool_response\n- ✅ Standard params: `temperature`, `top_p`, `seed`, `stop`, `n`, `user`, `presence_penalty`, `frequency_penalty`, `logit_bias`\n\n## PII handling\n\nทุก message scan ผ่าน Layer 1 (regex) + Layer 2 (Thai heuristic):\n\n1. **NONE** — ไม่พบ PII → ส่ง backend ตรงๆ\n2. **REDACTABLE** — พบ PII → tokenize → ส่ง backend → de-tokenize ก่อนคืน\n3. **SENSITIVE** — pin ไว้ที่ LOCAL tier เท่านั้น (ห้ามออกนอกประเทศ)\n\nดู `X-Gateway-PII-Class` ใน response header เพื่อรู้ว่า request ถูกจัดอย่างไร.\n\n## Audit\n\n`X-Gateway-Audit-Url` header → ตรวจสอบทุก detail per request ได้","operationId":"chat_completions_v1_chat_completions_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional RFC-style idempotency key. Same (tenant, key, body) within 24h replays the cached response (sub-second). Honored only for non-streaming chat — streaming responses skip cache.","title":"Idempotency-Key"},"description":"Optional RFC-style idempotency key. Same (tenant, key, body) within 24h replays the cached response (sub-second). Honored only for non-streaming chat — streaming responses skip cache."},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Chat Completions V1 Chat Completions Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/compose":{"post":{"tags":["Chat & Completions"],"summary":"Orchestrated write+judge+revise pipeline (KoishiAI/AInovel pattern)","description":"ทำงานเหมือน `/v1/chat/completions` แต่ทำ orchestrated pipeline ให้:\n\n```\nwriter  → editor judges →  if score < threshold:\n                              revise (≤ max_revisions)\n                              if still fail + use_fresh_think_fallback:\n                                fresh-think on DIFFERENT model\n```\n\nใช้ pattern จาก KoishiAI/AInovel — small writer + big editor + revise\nloop. **ค่า default routes ทุกอย่างใน-country** (local-writer / local-editor\n/ local-reasoner). ไม่จำเป็นต้องขึ้น frontier เลย.\n\nResponse มี `compose.trace` แสดงทุก step ที่ทำ — ตรวจสอบได้ว่า winning\ndraft มาจาก path ไหน.","operationId":"compose_endpoint_v1_compose_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional RFC-style idempotency key. Same (tenant, key, body) dedupes concurrent composes AND resumes from latest completed step on retry-after-crash (Phase D).","title":"Idempotency-Key"},"description":"Optional RFC-style idempotency key. Same (tenant, key, body) dedupes concurrent composes AND resumes from latest completed step on retry-after-crash (Phase D)."},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ComposeApiRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Compose Endpoint V1 Compose Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/smart":{"post":{"tags":["Chat & Completions"],"summary":"Auto-routing Smart Engine — customer sends intent, engine picks pack/schema/model/rubric","description":"**The flagship Smart Engine endpoint.** ลูกค้าส่งแค่ `messages` (natural\nlanguage); engine ตัดสินใจเองว่า:\n\n1. **Intent** (create/polish/analyze/recommend/research/explain/summarize)\n2. **Domain** (education / healthcare / finance / ...)\n3. **Subject** + **Level** (math, m4, vocational, ...)\n4. **Output schema** (JSON shape) จาก `schemas/<domain>/<intent>.json`\n5. **Editor rubric** จาก `rubrics/<domain>/<intent>.md`\n6. **Knowledge packs** ที่จะ inject (จาก pack router)\n7. **Writer + editor model** จาก role mapping\n\nลูกค้า override ได้ทุก field ถ้ารู้ดีกว่า engine — ทุก override field\noptional.\n\nResponse มี `smart.*` metadata ที่บอกว่า engine ตัดสินใจอะไรไปและทำไม\n— ใช้ debug + audit + Wewasanad UI โชว์ \"engine ใช้ pack อะไรเขียน\nบทเรียนนี้\" ได้.\n\n**Streaming** (B4): pass `stream: true` to get text/event-stream\nresponse with per-step SSE events. Required for external clients\nbehind CF Tunnel (100s edge timeout). Events flow:\n`smart.classified` → `smart.routed` → `compose.started` → `write.*`\n→ `judge.*` → (`revise.*`)? → (`fresh_think.*`)? → `compose.complete`\n→ `smart.enforce` → `smart.complete` → `[DONE]`.","operationId":"smart_endpoint_v1_smart_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional RFC-style idempotency key. Same (tenant, key, body) within 24h returns cached response.","title":"Idempotency-Key"},"description":"Optional RFC-style idempotency key. Same (tenant, key, body) within 24h returns cached response."},{"name":"X-Gateway-Inject-Check","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set to '1' or 'strict' to enable prompt-injection scanning. Returns 400 with `inject_detected` if Layer A rule pattern fires above threshold.","title":"X-Gateway-Inject-Check"},"description":"Set to '1' or 'strict' to enable prompt-injection scanning. Returns 400 with `inject_detected` if Layer A rule pattern fires above threshold."},{"name":"X-Compliance-Mode","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Per-request override of the tenant's compliance_mode. Values: 'off' | 'pdpa' | 'hipaa' | 'gdpr'. Lets a single bearer run both consumer (no enforcement) and regulated (PDPA-style hard-local) paths. Wins over tenant default.","title":"X-Compliance-Mode"},"description":"Per-request override of the tenant's compliance_mode. Values: 'off' | 'pdpa' | 'hipaa' | 'gdpr'. Lets a single bearer run both consumer (no enforcement) and regulated (PDPA-style hard-local) paths. Wins over tenant default."},{"name":"X-Semantic-Cache-Bypass","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Set to '1' to force a cache miss for this request — runs the full pipeline so ops can measure live latency or debug a suspected bad cached answer without clearing the cache for everyone else.","title":"X-Semantic-Cache-Bypass"},"description":"Set to '1' to force a cache miss for this request — runs the full pipeline so ops can measure live latency or debug a suspected bad cached answer without clearing the cache for everyone else."},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SmartApiRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Smart Endpoint V1 Smart Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/health":{"get":{"tags":["Health"],"summary":"Liveness probe","description":"ตรวจสอบว่า service ยังทำงานอยู่. ไม่ต้องการ authentication. ใช้สำหรับ load balancer / monitoring.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Health Get"},"example":{"status":"ok","version":"0.11.0"}}}}}}},"/health/backends":{"get":{"tags":["Health"],"summary":"Backend probe (no auth) — check tier availability + latency","description":"Probe each tier with a tiny request and report up/down + latency.\n\nใช้สำหรับ:\n- Wewasanad ระบบ monitoring เช็คก่อน route traffic\n- Debug ตอนลูกค้ารายงาน \"frontier ช้า\" — ตรวจได้ทันทีว่าใคร degraded\n\nไม่ต้องการ auth (เปิด public แต่ rate-limited ที่ CF level).","operationId":"health_backends_health_backends_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Health Backends Health Backends Get"}}}}}}},"/v1/jobs":{"post":{"tags":["Chat & Completions"],"summary":"Submit async compose job (returns 202 immediately)","description":"Same body shape as `/v1/smart` plus optional\n`webhook_url` + `webhook_secret`. Gateway returns 202 with `job_id`,\nruns compose in background, and POSTs result to webhook (HMAC signed\nvia `X-Gateway-Signature: <hex>` header).\n\nCustomer can also poll `GET /v1/jobs/{job_id}` for status + result.\n\nUse when `/v1/smart` would exceed CF Tunnel timeout (~100s) and\nstreaming isn't available (e.g. server-side cron tasks).","operationId":"submit_job_v1_jobs_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobSubmitIn"}}}},"responses":{"202":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Submit Job V1 Jobs Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"tags":["Chat & Completions"],"summary":"List this tenant's recent async jobs","operationId":"list_jobs_endpoint_v1_jobs_get","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/JobOut"},"title":"Response List Jobs Endpoint V1 Jobs Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/jobs/{job_id}":{"get":{"tags":["Chat & Completions"],"summary":"Get async job status + result","operationId":"get_job_endpoint_v1_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JobDetailOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/login":{"post":{"tags":["Admin"],"summary":"Owner login — verify password, issue session JWT","description":"Authenticate owner. On success, issue a JWT scoped to admin.\nFailure returns 401 with no detail leaked (don't say whether the\nid existed).","operationId":"login_endpoint_v1_admin_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/logout":{"post":{"tags":["Admin"],"summary":"Owner logout — client-side token discard (stateless server)","description":"JWT-based session has no server state to clear. Client just\ndiscards the token. Return 204 so dashboard can confirm.\n\nFuture: when we add JTI revocation table, this endpoint should\nrevoke the bearer token's jti so reuse is impossible.","operationId":"logout_endpoint_v1_admin_logout_post","responses":{"204":{"description":"Successful Response"}}}},"/v1/ocr/health":{"get":{"tags":["OCR"],"summary":"OCR pipeline liveness probe","description":"Returns 200 with pipeline state (which devices are loaded). OCR providers are lazy-loaded on first request per device, so `devices_ready: []` at startup is normal.","operationId":"ocr_health_v1_ocr_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/ocr/validate-id":{"post":{"tags":["OCR"],"summary":"Validate a Thai national ID checksum","description":"Lightweight mod-11 checksum validation. No image required. Same response shape as `idocr.kiatdamrong.shop/api/validate`.","operationId":"validate_id_v1_ocr_validate_id_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ValidateIdIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/ocr/thai-id":{"post":{"tags":["OCR"],"summary":"OCR a Thai national ID card","description":"Runs the Thai ID pipeline in-process and returns the extracted fields. Schema matches `idocr.kiatdamrong.shop/api/extract` (see `PUBLIC_API.md`) plus a `_gateway` meta block.\n\n**Cache:** Responses are cached by SHA1(image) for 1 hour (per tenant). A duplicate upload returns the cached result in ~5ms with `_gateway.cached: true`.\n\n**PDPA:** PII (id_number, names) is **NOT** redacted by default — the personal data is the answer you paid for. Send header `X-Gateway-PDPA: 1` to enable redaction (rare; typically only for masked-card-preview UX).","operationId":"ocr_thai_id_v1_ocr_thai_id_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_ocr_thai_id_v1_ocr_thai_id_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/ocr/verify-ekyc":{"post":{"tags":["OCR"],"summary":"eKYC verify — compare user-entered form against OCR'd card","description":"Customer's user fills the form (=truth 100%). Server OCRs the uploaded card image and fuzzy-matches each field. Returns `pass` if core fields (id_number / first_name / last_name / birth_date) all match, otherwise `review` with per-field reasons.\n\nSchema matches `idocr.kiatdamrong.shop/api/verify-ekyc` plus a `_gateway` meta block. No cache (verify outcome depends on the form fields, not just the image).","operationId":"verify_ekyc_v1_ocr_verify_ekyc_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_verify_ekyc_v1_ocr_verify_ekyc_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/ocr/geo":{"get":{"tags":["OCR"],"summary":"Thai administrative gazetteer (77 provinces / 930 districts / 7452 subdistricts)","description":"Hierarchical tree of Thai provinces → districts → subdistricts (kongvut/thai-province-data, MIT). Use to power cascading dropdowns or to normalize OCR'd place names against a closed set. Cached server-side for 24h (the data changes maybe yearly).","operationId":"geo_v1_ocr_geo_get","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants":{"get":{"tags":["Admin"],"summary":"List tenants (admin)","operationId":"list_tenants_v1_admin_tenants_get","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TenantOut"},"title":"Response List Tenants V1 Admin Tenants Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Admin"],"summary":"Create tenant (admin)","operationId":"create_tenant_endpoint_v1_admin_tenants_post","parameters":[{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantCreateIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}":{"get":{"tags":["Admin"],"summary":"Get tenant (admin)","operationId":"get_tenant_v1_admin_tenants__tenant_id__get","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"tags":["Admin"],"summary":"Update tenant (admin, partial — only set fields are changed)","operationId":"update_tenant_endpoint_v1_admin_tenants__tenant_id__put","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantUpdateIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Admin"],"summary":"Delete tenant (admin, demo tenant protected)","operationId":"delete_tenant_endpoint_v1_admin_tenants__tenant_id__delete","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Tenant Endpoint V1 Admin Tenants  Tenant Id  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/tokens":{"post":{"tags":["Admin"],"summary":"Issue an API key (JWT) for a tenant","description":"Mint a new JWT for the given tenant.\n\nThe customer gets `token` — they put it in `Authorization: Bearer <token>`.\nSave the `jti` — that's how you later revoke this specific key.","operationId":"issue_token_endpoint_v1_admin_tenants__tenant_id__tokens_post","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueTokenIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueTokenOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/tokens/{jti}":{"delete":{"tags":["Admin"],"summary":"Revoke an API key by jti","description":"Add `jti` to the revocation deny-list. Any future request bearing\nthis token returns 401. Idempotent: revoking twice is harmless.","operationId":"revoke_token_endpoint_v1_admin_tenants__tenant_id__tokens__jti__delete","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"jti","in":"path","required":true,"schema":{"type":"string","title":"Jti"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Revoke Token Endpoint V1 Admin Tenants  Tenant Id  Tokens  Jti  Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/admin/tenants/{tenant_id}/tokens/rotate":{"post":{"tags":["Admin"],"summary":"Rotate: revoke an old key + issue a new one in one call","description":"Atomic rotation pattern. Customer can call this on a schedule\n(cron) to keep key lifetime bounded without API downtime — issue\nfirst, then revoke the old jti.","operationId":"rotate_token_endpoint_v1_admin_tenants__tenant_id__tokens_rotate_post","parameters":[{"name":"tenant_id","in":"path","required":true,"schema":{"type":"string","title":"Tenant Id"}},{"name":"old_jti","in":"query","required":true,"schema":{"type":"string","title":"Old Jti"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueTokenIn"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/IssueTokenOut"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/exam":{"post":{"tags":["Demo Tasks"],"summary":"(Demo) สร้างข้อสอบจากหัวข้อ — JSON-mode example","description":"**Demo endpoint** — ตัวอย่าง JSON-schema-validated task.\nลูกค้า production ควรประกอบเองผ่าน `/v1/chat/completions` +\n`response_format={\"type\":\"json_object\"}` + prompt ของตัวเอง.","operationId":"exam_endpoint_v1_exam_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExamRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExamPayload"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/analyze-csv":{"post":{"tags":["Demo Tasks"],"summary":"(Demo) วิเคราะห์ CSV ทั่วไป — HARD RULE #5 example","description":"**Demo endpoint** — generic CSV tabular analysis. ลูกค้า production ใช้ `/v1/cohorts/analyze` (LMS-shaped) หรือประกอบเองผ่าน chat","operationId":"analyze_csv_endpoint_v1_analyze_csv_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_analyze_csv_endpoint_v1_analyze_csv_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Analyze Csv Endpoint V1 Analyze Csv Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/charts/render":{"post":{"tags":["Tool Layer"],"summary":"Render chart (PNG / SVG / Vega-Lite spec)","description":"**Tool Layer endpoint** (spec §4) — deterministic, no LLM.\nลูกค้าส่ง chart spec + data → คืน PNG base64 / raw SVG / Vega-Lite spec.\nSupported chart types: histogram, bar, pie, scatter, line, boxplot.","operationId":"chart_render_endpoint_v1_charts_render_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChartRenderRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChartRenderResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/cohorts/analyze":{"post":{"tags":["Demo Tasks"],"summary":"(Demo) LMS cohort at-risk analysis — Thai education context","description":"**Demo endpoint** สำหรับ Thai LMS context. HARD RULE #4 (at-risk\nidentification is rule-based) + #5 (raw rows compute in-country, LLM sees digest only).","operationId":"cohort_analyze_endpoint_v1_cohorts_analyze_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_cohort_analyze_endpoint_v1_cohorts_analyze_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CohortAnalysisResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tools/web_search":{"post":{"tags":["Grounding"],"summary":"ค้นเว็บจริง (SearXNG) — คืน title+url+snippet","description":"ค้นข้อมูลจริงจากเว็บ ใช้เป็น grounding tool ของ agentic writer/judge เพื่อให้ AI อ้างอิงแหล่งจริง ไม่แต่งขึ้นเอง.","operationId":"web_search_endpoint_v1_tools_web_search_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebSearchRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Web Search Endpoint V1 Tools Web Search Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tools/read_url":{"post":{"tags":["Grounding"],"summary":"อ่านเนื้อหาจริงจาก URL (HTML/PDF) — SSRF-guarded","description":"ดึงข้อความสะอาดจาก url (HTML ผ่าน trafilatura, PDF ผ่าน PyMuPDF + ซ่อมสระไทย). บล็อก private/loopback IP (กัน SSRF). ใช้ให้ AI อ่านบทความจริงก่อนสรุป ไม่จินตนาการเอง.","operationId":"read_url_endpoint_v1_tools_read_url_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReadUrlRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Read Url Endpoint V1 Tools Read Url Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/tools/read_file":{"post":{"tags":["Grounding"],"summary":"ดึงข้อความจากไฟล์ที่อัปโหลด (PDF / DOCX / XLSX / CSV / TXT)","description":"ใช้สำหรับให้ผู้ใช้งานอัปโหลดเอกสารจริง แล้ว AI ถอด/วิเคราะห์/สรุปได้.\n- PDF → PyMuPDF (ดึงข้อความ + ซ่อมสระไทย ำ ที่แตก)\n- DOCX → python-docx (รวม paragraph + table)\n- XLSX → openpyxl (ทุก sheet, cap 500 rows/sheet)\n- CSV/TSV → stdlib csv (cap 500 rows)\n- TXT/MD → ลอง UTF-8 → CP874 → Latin-1\n**ขนาดไฟล์ไม่เกิน 10MB** · **ข้อความที่ดึงออกถูก cap ที่ ~30000 ตัวอักษร**.","operationId":"read_file_endpoint_v1_tools_read_file_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_read_file_endpoint_v1_tools_read_file_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Read File Endpoint V1 Tools Read File Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/packs/{pack_id}/draft-from-url":{"post":{"tags":["Knowledge"],"summary":"(admin) ดึงเนื้อหาจริงจาก URL → สร้าง draft chunk รอ review","description":"**Knowledge flywheel — step 1 (admin-only).** ดึงเนื้อหาจริง\nจาก URL (HTML หรือ PDF) ผ่าน `read_url` (SSRF-guarded) → ให้ writer สรุปเป็น\nchunk คุณภาพ pack → save ลง `packs/<pack_id>/drafts/<draft_id>.md` พร้อม\nfrontmatter (source_url, fetched_at, kind). **ยังไม่ ingest** — รอ admin\nreview ก่อน (anti-fabrication: ทุก chunk ใน sources ต้องผ่านสายตา curator).","operationId":"draft_from_url_endpoint_v1_packs__pack_id__draft_from_url_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DraftFromUrlRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Draft From Url Endpoint V1 Packs  Pack Id  Draft From Url Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/packs/{pack_id}/drafts":{"get":{"tags":["Knowledge"],"summary":"(admin) ลิสต์ draft chunks ที่รอ review ใน pack นี้","operationId":"list_drafts_endpoint_v1_packs__pack_id__drafts_get","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response List Drafts Endpoint V1 Packs  Pack Id  Drafts Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/packs/{pack_id}/drafts/{draft_id}":{"get":{"tags":["Knowledge"],"summary":"(admin) อ่านเนื้อ draft เต็ม (markdown + frontmatter)","operationId":"read_draft_endpoint_v1_packs__pack_id__drafts__draft_id__get","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"draft_id","in":"path","required":true,"schema":{"type":"string","title":"Draft Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Read Draft Endpoint V1 Packs  Pack Id  Drafts  Draft Id  Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/packs/{pack_id}/drafts/{draft_id}/approve":{"post":{"tags":["Knowledge"],"summary":"(admin) อนุมัติ draft → ย้ายเข้า sources/ + re-embed pack","description":"ย้ายไฟล์ `drafts/<id>.md` → `sources/<id>.md` แล้วเรียก `packs.ingest()` ให้ pack สร้าง chunks + embeddings ใหม่. หลังจากนี้ writer/judge ตัวอื่นค้นเจอ chunk นี้ได้ผ่าน `/v1/knowledge/query`.","operationId":"approve_draft_endpoint_v1_packs__pack_id__drafts__draft_id__approve_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"draft_id","in":"path","required":true,"schema":{"type":"string","title":"Draft Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Approve Draft Endpoint V1 Packs  Pack Id  Drafts  Draft Id  Approve Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/packs/{pack_id}/drafts/{draft_id}/reject":{"post":{"tags":["Knowledge"],"summary":"(admin) ปฏิเสธ draft → ลบไฟล์ ไม่เข้า pack","operationId":"reject_draft_endpoint_v1_packs__pack_id__drafts__draft_id__reject_post","parameters":[{"name":"pack_id","in":"path","required":true,"schema":{"type":"string","title":"Pack Id"}},{"name":"draft_id","in":"path","required":true,"schema":{"type":"string","title":"Draft Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Reject Draft Endpoint V1 Packs  Pack Id  Drafts  Draft Id  Reject Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/wizard/polish":{"post":{"tags":["Wizard"],"summary":"ขัดเกลาภาษาไทยให้เป็นเนทีฟ (fix translationese)","description":"**Wizard facade** — รับข้อความไทยเข้ามา คืนเวอร์ชันที่ขัดเกลาแล้ว.\nเหมาะกับ integrator ที่ใช้ Claude/GPT/Gemini เขียนไทยแล้วได้สำนวนแปลตรงตัว\n(\"ที่ซึ่ง / ถูกทำให้ / ทำการ-\") — POST มาที่นี่ก็ได้ผลลัพธ์เนทีฟ ไม่ต้องเขียน\nprompt + glue เอง.\n\nภายในคือ Smart Engine — preset writer-only (ไม่มี judge, ไม่มี pack, ไม่มี schema).\nได้ฟีเจอร์ครบของ Smart Engine ฟรี: PDPA gate, audit trail, load-aware\noffload, idempotency, streaming, rate limit.","operationId":"polish_endpoint_v1_wizard_polish_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PolishRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Polish Endpoint V1 Wizard Polish Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/wizard/fact-check":{"post":{"tags":["Wizard"],"summary":"ตรวจข้อความ/แผน/บทความ ด้วย judge ที่ใช้เครื่องมือ ground แหล่งจริง","description":"**Wizard facade (= D, agentic grounded judge).** ส่งข้อความ\nเข้ามา ระบบจะให้ judge ค้นหาแหล่งจริง (คลังความรู้/เว็บ/อ่าน url) ก่อนให้คะแนน\nและทุก issue จะมีที่มาที่ตรวจสอบได้.\n\nPDPA: ใช้กับเนื้อหาที่ **ไม่มี PII** เท่านั้น (เพราะ judge cloud จะเห็น draft).\nถ้ามี PII ระบบจะ fall back เป็น judge local โดยอัตโนมัติ.","operationId":"fact_check_endpoint_v1_wizard_fact_check_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FactCheckRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Fact Check Endpoint V1 Wizard Fact Check Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/wizard/grounded-summarize":{"post":{"tags":["Wizard"],"summary":"สังเคราะห์ข้อมูลจากแหล่งจริง ด้วย writer ที่ใช้เครื่องมืออ่านก่อนตอบ","description":"**Wizard facade (= A-prod, grounded agentic writer).**\nส่งคำถามเข้ามา writer จะค้น+อ่านแหล่งจริง (lookup_knowledge / web_search /\nread_url) ก่อนสังเคราะห์คำตอบ. คำตอบมี citations ที่ตรวจสอบได้.\n\nระบบมี **citation verifier**: ทุก URL ที่อ้างในคำตอบจะถูกเทียบกับสิ่งที่\nwriter เปิดอ่านจริง. URL ที่ \"อ้างแต่ไม่ได้อ่าน\" จะอยู่ใน\n`writer_grounding.citations.fabricated_list`.\n\nPDPA: ใช้กับเนื้อหา **ไม่มี PII** เท่านั้น.","operationId":"grounded_summarize_endpoint_v1_wizard_grounded_summarize_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroundedSummarizeRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Grounded Summarize Endpoint V1 Wizard Grounded Summarize Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/wizard/translate-th":{"post":{"tags":["Wizard"],"summary":"แปลภาษาใดก็ได้เป็นภาษาไทยที่เป็นเจ้าของภาษา","description":"**Wizard facade** — แปลข้อความเป็นภาษาไทยโดยตรง.\nใช้ Typhoon (Thai-native) เป็น writer → output ไม่มี translationese\n('ที่ซึ่ง / ถูกทำให้') ที่เกิดเมื่อแปลโดย Claude/GPT/Gemini.\n\nPDPA: ใช้ smart-engine routing — PII pins LOCAL อัตโนมัติ.","operationId":"translate_th_endpoint_v1_wizard_translate_th_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TranslateThRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Translate Th Endpoint V1 Wizard Translate Th Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/wizard/shorten":{"post":{"tags":["Wizard"],"summary":"ตัดทอนข้อความให้สั้นโดยรักษาน้ำเสียงและข้อเท็จจริง","description":"**Wizard facade** — รับข้อความยาว ส่งกลับเวอร์ชันสั้น.\nไม่ใช่ summary (สรุปย่อ) แต่เป็น `tightening` — ตัดความซ้ำ คำฟุ่มเฟือย\nคงลำดับและน้ำเสียงเดิมไว้ครบ. เหมาะสำหรับ SMS / push notification /\ntweet / meta description ที่มี draft ยาวอยู่แล้ว.\n\nPDPA: smart-engine routing.","operationId":"shorten_endpoint_v1_wizard_shorten_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShortenRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Shorten Endpoint V1 Wizard Shorten Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/wizard/fix-thai":{"post":{"tags":["Wizard"],"summary":"แก้สะกด/วรรค/วรรณยุกต์โดยไม่เปลี่ยนสำนวน","description":"**Wizard facade** — proofreading-only.\nต่างจาก `/v1/wizard/polish` — polish เปลี่ยนสำนวนแปลตรงตัวเป็นไทยเนทีฟ\n(rewrite ระดับประโยค); fix-thai แก้เฉพาะสะกดผิด/วรรคผิด/วรรณยุกต์หาย\n(word-level). ถ้าต้องการทั้งสอง: เรียก fix-thai → polish ตามลำดับ.\n\nPDPA: smart-engine routing.","operationId":"fix_thai_endpoint_v1_wizard_fix_thai_post","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Idempotency-Key"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FixThaiRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Fix Thai Endpoint V1 Wizard Fix Thai Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/docintel/extract":{"post":{"tags":["Document Intelligence"],"summary":"Submit Extract","description":"Submit document for async extraction. Returns job_id immediately.\n\nSupported file types: PDF, PNG, JPG, JPEG, WEBP. Max 30MB.\nBackends: 'local' (DGX Ollama) or 'cloud' (Typhoon Cloud, faster).\nUse GET /v1/docintel/jobs/{job_id} to poll.","operationId":"submit_extract_v1_docintel_extract_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_submit_extract_v1_docintel_extract_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/docintel/extract-id":{"post":{"tags":["Document Intelligence"],"summary":"Submit Extract Id","description":"Submit Thai ID card for async extraction (single page, ID-specific extractors).","operationId":"submit_extract_id_v1_docintel_extract_id_post","parameters":[{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_submit_extract_id_v1_docintel_extract_id_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/docintel/jobs/{job_id}":{"get":{"tags":["Document Intelligence"],"summary":"Get Job","description":"Poll job status. Returns full result when status='done'.\n\nTenant isolation: a tenant only sees their own jobs.","operationId":"get_job_v1_docintel_jobs__job_id__get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"string","title":"Job Id"}},{"name":"x-user-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-User-Id"}},{"name":"x-product-id","in":"header","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X-Product-Id"}},{"name":"authorization","in":"header","required":false,"schema":{"type":"string","default":"","title":"Authorization"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/v1/docintel/health":{"get":{"tags":["Document Intelligence"],"summary":"Health","description":"Lightweight liveness + version check. No auth required.","operationId":"health_v1_docintel_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/v1/docintel/doc-types":{"get":{"tags":["Document Intelligence"],"summary":"Doc Types","description":"Catalog of supported document types.","operationId":"doc_types_v1_docintel_doc_types_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"AtRiskStudent":{"properties":{"student_id":{"type":"string","title":"Student Id","description":"Original ID from customer CSV (mapped back in-country)"},"risk_level":{"type":"string","enum":["high","medium","low"],"title":"Risk Level"},"risk_factors":{"items":{"type":"string"},"type":"array","title":"Risk Factors","description":"Which criteria triggered (e.g., 'score_low', 'attendance_low')"},"score":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Score","description":"Primary metric value"},"recommendation":{"type":"string","title":"Recommendation","description":"Suggested intervention"}},"type":"object","required":["student_id","risk_level","risk_factors","recommendation"],"title":"AtRiskStudent"},"AuditTrail":{"properties":{"classification":{"type":"string","title":"Classification"},"pii_categories_detected":{"items":{"type":"string"},"type":"array","title":"Pii Categories Detected"},"rows_processed":{"type":"integer","title":"Rows Processed"},"computation_location":{"type":"string","title":"Computation Location","default":"TH"},"raw_data_sent_external":{"type":"boolean","title":"Raw Data Sent External","default":false},"digest_chars_sent_to_llm":{"type":"integer","title":"Digest Chars Sent To Llm","default":0}},"type":"object","required":["classification","pii_categories_detected","rows_processed"],"title":"AuditTrail"},"Body_analyze_csv_endpoint_v1_analyze_csv_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"question":{"type":"string","title":"Question"},"model":{"type":"string","title":"Model","default":"local-fast"}},"type":"object","required":["file","question"],"title":"Body_analyze_csv_endpoint_v1_analyze_csv_post"},"Body_cohort_analyze_endpoint_v1_cohorts_analyze_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"question":{"type":"string","title":"Question"},"model":{"type":"string","title":"Model","default":"frontier-gemini"},"language":{"type":"string","title":"Language","default":"Thai"}},"type":"object","required":["file","question"],"title":"Body_cohort_analyze_endpoint_v1_cohorts_analyze_post"},"Body_ocr_thai_id_v1_ocr_thai_id_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"Card image (jpg/png/webp)"},"device":{"type":"string","title":"Device","description":"\"gpu\" or \"cpu\"; default = server config"}},"type":"object","required":["file"],"title":"Body_ocr_thai_id_v1_ocr_thai_id_post"},"Body_read_file_endpoint_v1_tools_read_file_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"max_chars":{"type":"integer","title":"Max Chars","default":30000}},"type":"object","required":["file"],"title":"Body_read_file_endpoint_v1_tools_read_file_post"},"Body_retention_erase_endpoint_v1_admin_retention_erase_post":{"properties":{"tenant_id":{"type":"string","title":"Tenant Id","description":"Tenant whose data to erase"},"operator":{"type":"string","title":"Operator","description":"Who is performing the erasure"},"reason":{"type":"string","title":"Reason","description":"Why (data subject letter ID, ticket, etc.)"}},"type":"object","required":["tenant_id","operator","reason"],"title":"Body_retention_erase_endpoint_v1_admin_retention_erase_post"},"Body_submit_extract_id_v1_docintel_extract_id_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"preprocess":{"type":"boolean","title":"Preprocess","default":true},"enable_ensemble":{"type":"boolean","title":"Enable Ensemble","default":false},"enable_vision_check":{"type":"boolean","title":"Enable Vision Check","default":false},"backend":{"type":"string","title":"Backend","default":"cloud"}},"type":"object","required":["file"],"title":"Body_submit_extract_id_v1_docintel_extract_id_post"},"Body_submit_extract_v1_docintel_extract_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"preprocess":{"type":"boolean","title":"Preprocess","default":true},"enable_ensemble":{"type":"boolean","title":"Enable Ensemble","default":false},"enable_vision_check":{"type":"boolean","title":"Enable Vision Check","default":false},"enable_mrz":{"type":"boolean","title":"Enable Mrz","default":false},"backend":{"type":"string","title":"Backend","default":"cloud"}},"type":"object","required":["file"],"title":"Body_submit_extract_v1_docintel_extract_post"},"Body_upload_document_v1_corpus__corpus_id__documents_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"embed":{"type":"boolean","title":"Embed","default":true}},"type":"object","required":["file"],"title":"Body_upload_document_v1_corpus__corpus_id__documents_post"},"Body_upload_source_v1_admin_packs__pack_id__sources_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File"},"target":{"type":"string","title":"Target","description":"'draft' (default, needs review) or 'live' (skip review)","default":"draft"}},"type":"object","required":["file"],"title":"Body_upload_source_v1_admin_packs__pack_id__sources_post"},"Body_verify_ekyc_v1_ocr_verify_ekyc_post":{"properties":{"file":{"type":"string","contentMediaType":"application/octet-stream","title":"File","description":"Card image (jpg/png/webp)"},"first_name":{"type":"string","title":"First Name","default":""},"last_name":{"type":"string","title":"Last Name","default":""},"house":{"type":"string","title":"House","default":""},"moo":{"type":"string","title":"Moo","default":""},"tambon":{"type":"string","title":"Tambon","default":""},"amphoe":{"type":"string","title":"Amphoe","default":""},"province":{"type":"string","title":"Province","default":""},"birth_date":{"type":"string","title":"Birth Date","default":""},"id_number":{"type":"string","title":"Id Number","default":""},"device":{"type":"string","title":"Device"}},"type":"object","required":["file"],"title":"Body_verify_ekyc_v1_ocr_verify_ekyc_post"},"CancelResult":{"properties":{"tenant":{"type":"string","title":"Tenant"},"cancelled":{"type":"integer","title":"Cancelled"},"rids":{"items":{"type":"string"},"type":"array","title":"Rids"}},"type":"object","required":["tenant","cancelled","rids"],"title":"CancelResult"},"ChartRenderRequest":{"properties":{"chart":{"$ref":"#/components/schemas/ChartSpec"},"format":{"type":"string","enum":["png","svg","vega-lite"],"title":"Format","default":"png"},"width":{"type":"integer","maximum":4000.0,"minimum":200.0,"title":"Width","default":800},"height":{"type":"integer","maximum":4000.0,"minimum":200.0,"title":"Height","default":600},"dpi":{"type":"integer","maximum":200.0,"minimum":50.0,"title":"Dpi","default":100}},"type":"object","required":["chart"],"title":"ChartRenderRequest"},"ChartRenderResponse":{"properties":{"format":{"type":"string","title":"Format"},"chart_type":{"type":"string","title":"Chart Type"},"width":{"type":"integer","title":"Width"},"height":{"type":"integer","title":"Height"},"render_ms":{"type":"integer","title":"Render Ms"},"image_base64":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Image Base64"},"svg":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Svg"},"vega_lite_spec":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Vega Lite Spec"},"size_bytes":{"type":"integer","title":"Size Bytes","default":0}},"type":"object","required":["format","chart_type","width","height","render_ms"],"title":"ChartRenderResponse"},"ChartSpec":{"properties":{"type":{"type":"string","enum":["histogram","bar","scatter","line","boxplot","pie"],"title":"Type"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"x_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"X Label"},"y_label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Y Label"},"values":{"anyOf":[{"items":{"type":"number"},"type":"array"},{"type":"null"}],"title":"Values"},"groups":{"anyOf":[{"additionalProperties":{"items":{"type":"number"},"type":"array"},"type":"object"},{"type":"null"}],"title":"Groups"},"categories":{"anyOf":[{"additionalProperties":{"type":"number"},"type":"object"},{"type":"null"}],"title":"Categories"},"points":{"anyOf":[{"items":{"additionalProperties":{"type":"number"},"type":"object"},"type":"array"},{"type":"null"}],"title":"Points"},"series":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Series"},"bins":{"type":"integer","title":"Bins","default":20},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color"}},"type":"object","required":["type"],"title":"ChartSpec","description":"One chart definition. Different fields used per chart type."},"ChatMessage":{"properties":{"role":{"type":"string","title":"Role"},"content":{"anyOf":[{"type":"string"},{"items":{"additionalProperties":true,"type":"object"},"type":"array"}],"title":"Content"}},"type":"object","required":["role","content"],"title":"ChatMessage"},"ChatRequest":{"properties":{"model":{"type":"string","title":"Model"},"messages":{"items":{"$ref":"#/components/schemas/ChatMessage"},"type":"array","minItems":1,"title":"Messages"},"temperature":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Temperature"},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"stream":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Stream","default":false},"tools":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Tools"},"tool_choice":{"anyOf":[{"type":"string"},{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Tool Choice"},"response_format":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Response Format"},"top_p":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Top P"},"n":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"N"},"stop":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Stop"},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed"},"user":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User"},"presence_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Presence Penalty"},"frequency_penalty":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Frequency Penalty"},"logit_bias":{"anyOf":[{"additionalProperties":{"type":"number"},"type":"object"},{"type":"null"}],"title":"Logit Bias"},"cache_control":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Cache Control"}},"type":"object","required":["model","messages"],"title":"ChatRequest"},"CohortAnalysisResponse":{"properties":{"request_id":{"type":"string","title":"Request Id"},"cohort_stats":{"$ref":"#/components/schemas/CohortStats"},"insights":{"items":{"$ref":"#/components/schemas/Insight"},"type":"array","title":"Insights"},"at_risk_students":{"items":{"$ref":"#/components/schemas/AtRiskStudent"},"type":"array","title":"At Risk Students"},"visualization_hints":{"items":{"$ref":"#/components/schemas/VisualizationHint"},"type":"array","title":"Visualization Hints"},"audit":{"$ref":"#/components/schemas/AuditTrail"},"model_used":{"type":"string","title":"Model Used"},"tier_used":{"type":"string","title":"Tier Used"},"elapsed_ms":{"type":"integer","title":"Elapsed Ms"},"degraded":{"type":"boolean","title":"Degraded","default":false},"degraded_reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Degraded Reason"}},"type":"object","required":["request_id","cohort_stats","insights","at_risk_students","visualization_hints","audit","model_used","tier_used","elapsed_ms"],"title":"CohortAnalysisResponse"},"CohortStats":{"properties":{"n_students":{"type":"integer","title":"N Students"},"primary_metric":{"anyOf":[{"$ref":"#/components/schemas/PrimaryMetric"},{"type":"null"}]},"distributions":{"additionalProperties":{"additionalProperties":{"type":"integer"},"type":"object"},"type":"object","title":"Distributions"}},"type":"object","required":["n_students"],"title":"CohortStats"},"ComposeApiRequest":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/ComposeMessage"},"type":"array","title":"Messages"},"writer_model":{"type":"string","title":"Writer Model","default":"local-writer"},"editor_model":{"type":"string","title":"Editor Model","default":"local-editor"},"fallback_model":{"type":"string","title":"Fallback Model","default":"local-reasoner"},"editor_score_threshold":{"type":"integer","title":"Editor Score Threshold","default":70},"min_body_chars":{"type":"integer","title":"Min Body Chars","default":0},"max_revisions":{"type":"integer","title":"Max Revisions","default":1},"use_fresh_think_fallback":{"type":"boolean","title":"Use Fresh Think Fallback","default":true},"writer_options":{"additionalProperties":true,"type":"object","title":"Writer Options"},"editor_options":{"additionalProperties":true,"type":"object","title":"Editor Options"},"knowledge_packs":{"items":{"$ref":"#/components/schemas/KnowledgePackRef"},"type":"array","title":"Knowledge Packs"}},"type":"object","required":["messages"],"title":"ComposeApiRequest"},"ComposeMessage":{"properties":{"role":{"type":"string","title":"Role"},"content":{"anyOf":[{"type":"string"},{"items":{"additionalProperties":true,"type":"object"},"type":"array"}],"title":"Content"}},"type":"object","required":["role","content"],"title":"ComposeMessage"},"CreateCorpusBody":{"properties":{"name":{"type":"string","maxLength":200,"minLength":1,"title":"Name"}},"type":"object","required":["name"],"title":"CreateCorpusBody"},"DeepResearchBody":{"properties":{"question":{"type":"string","maxLength":4000,"minLength":1,"title":"Question"},"corpus_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Corpus Id"},"packs":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":10},{"type":"null"}],"title":"Packs","description":"knowledge pack ids ที่อนุญาตให้ใช้ — มากกว่า L1 (10 vs 5) เพราะ planner เลือก hint_packs ต่อบทเอง"},"pii_mode":{"type":"string","title":"Pii Mode","default":"local_only"},"depth":{"type":"string","title":"Depth","description":"normal=3 hops/section, deep=5, extensive=7 + critic","default":"normal"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"}},"type":"object","required":["question"],"title":"DeepResearchBody"},"DraftFromUrlRequest":{"properties":{"url":{"type":"string","title":"Url"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"}},"type":"object","required":["url"],"title":"DraftFromUrlRequest"},"EmbeddingRequest":{"properties":{"model":{"type":"string","title":"Model"},"input":{"anyOf":[{"type":"string"},{"items":{"type":"string"},"type":"array"}],"title":"Input"},"encoding_format":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Encoding Format","default":"float"}},"type":"object","required":["model","input"],"title":"EmbeddingRequest"},"ExamPayload":{"properties":{"topic":{"type":"string","title":"Topic"},"difficulty":{"type":"string","title":"Difficulty"},"questions":{"items":{"$ref":"#/components/schemas/ExamQuestion"},"type":"array","minItems":1,"title":"Questions"}},"type":"object","required":["topic","difficulty","questions"],"title":"ExamPayload"},"ExamQuestion":{"properties":{"question":{"type":"string","minLength":1,"title":"Question"},"options":{"items":{"type":"string"},"type":"array","maxItems":6,"minItems":2,"title":"Options"},"correct_index":{"type":"integer","title":"Correct Index"},"explanation":{"type":"string","title":"Explanation","default":""}},"type":"object","required":["question","options","correct_index"],"title":"ExamQuestion"},"ExamRequest":{"properties":{"topic":{"type":"string","title":"Topic"},"n_questions":{"type":"integer","title":"N Questions","default":5},"difficulty":{"type":"string","title":"Difficulty","default":"medium"},"language":{"type":"string","title":"Language","default":"Thai"},"model":{"type":"string","title":"Model","default":"local-fast"}},"type":"object","required":["topic"],"title":"ExamRequest"},"ExportBody":{"properties":{"markdown":{"type":"string","minLength":1,"title":"Markdown"},"format":{"type":"string","title":"Format","default":"docx"},"title":{"type":"string","maxLength":200,"title":"Title","default":"รายงาน"},"author":{"type":"string","maxLength":200,"title":"Author","default":""}},"type":"object","required":["markdown"],"title":"ExportBody"},"FactCheckRequest":{"properties":{"claim":{"type":"string","minLength":1,"title":"Claim","description":"ข้อความ/แผน/บทความที่ต้องตรวจ"},"pack_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Pack Id","description":"คลังความรู้ที่จะใช้อ้างอิง (default: pedagogy-th)"},"editor_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Editor Model","description":"โมเดล judge — ต้องเป็น cloud (PII-free เท่านั้น)"},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Backend tier for the judge step. 'standard' (default) | 'premium' (Gemini Flash) | 'frontier' (Claude Haiku). PII-bearing prompts pin LOCAL regardless."}},"type":"object","required":["claim"],"title":"FactCheckRequest"},"FillGapBody":{"properties":{"pack_id":{"type":"string","title":"Pack Id"},"query":{"type":"string","maxLength":500,"minLength":2,"title":"Query"},"urls":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":5},{"type":"null"}],"title":"Urls","description":"ระบุ URL เอง; ไม่ระบุ = web_search หาให้"},"max_sources":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Max Sources","default":2}},"type":"object","required":["pack_id","query"],"title":"FillGapBody"},"FixThaiRequest":{"properties":{"text":{"type":"string","minLength":1,"title":"Text","description":"ข้อความภาษาไทยที่อาจมีสะกดผิด/วรรคผิด"},"writer_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Writer Model","description":"Override writer model. Default: WIZARD_POLISH_WRITER."},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Backend tier for judge. 'standard' | 'premium' | 'frontier'. PII pins LOCAL."}},"type":"object","required":["text"],"title":"FixThaiRequest"},"GroundedSummarizeRequest":{"properties":{"question":{"type":"string","minLength":1,"title":"Question","description":"คำถาม/หัวข้อให้สังเคราะห์"},"urls":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Urls","description":"URL ที่ต้องการให้อ่านก่อน (optional ป้อนถ้ามี)"},"writer_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Writer Model","description":"โมเดล writer — ต้องเป็น cloud (PII-free เท่านั้น)"},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Backend tier for the judge step. 'standard' (default) | 'premium' (Gemini Flash) | 'frontier' (Claude Haiku). PII-bearing prompts pin LOCAL regardless."}},"type":"object","required":["question"],"title":"GroundedSummarizeRequest"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InflightList":{"properties":{"tenant":{"type":"string","title":"Tenant"},"count":{"type":"integer","title":"Count"},"slots":{"items":{"$ref":"#/components/schemas/InflightSlot"},"type":"array","title":"Slots"}},"type":"object","required":["tenant","count","slots"],"title":"InflightList"},"InflightSlot":{"properties":{"rid":{"type":"string","title":"Rid"},"state":{"type":"string","title":"State"},"owner":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Owner"},"started_at_ms":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Started At Ms"},"age_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Age S"},"is_stream":{"type":"boolean","title":"Is Stream","default":false},"hash_key":{"type":"string","title":"Hash Key"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["rid","state","hash_key"],"title":"InflightSlot"},"InflightStats":{"properties":{"tenant":{"type":"string","title":"Tenant"},"inflight_total":{"type":"integer","title":"Inflight Total"},"streaming":{"type":"integer","title":"Streaming"},"median_age_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Median Age S"},"p95_age_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"P95 Age S"},"oldest_age_s":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Oldest Age S"}},"type":"object","required":["tenant","inflight_total","streaming","median_age_s","p95_age_s","oldest_age_s"],"title":"InflightStats"},"Insight":{"properties":{"type":{"type":"string","enum":["trend","outlier","correlation","gap","strength"],"title":"Type"},"title":{"type":"string","title":"Title"},"summary":{"type":"string","title":"Summary"},"evidence":{"type":"string","title":"Evidence","description":"Specific numeric evidence from digest"}},"type":"object","required":["type","title","summary","evidence"],"title":"Insight"},"IssueBody":{"properties":{"scopes":{"items":{"type":"string"},"type":"array","maxItems":20,"minItems":1,"title":"Scopes"},"ttl_seconds":{"type":"integer","maximum":315360000.0,"minimum":3600.0,"title":"Ttl Seconds","description":"Token lifetime (default 90 days, min 1h, max 10y)","default":7776000},"product_id":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Product Id","description":"Optional product label baked into the JWT — every request using this token is tagged in audit + Prometheus without the client needing to send X-Product-Id."},"label":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Label","description":"Human-readable label for admin listing"}},"type":"object","required":["scopes"],"title":"IssueBody"},"IssueResponse":{"properties":{"jti":{"type":"string","title":"Jti"},"token":{"type":"string","title":"Token"},"sub":{"type":"string","title":"Sub"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"product_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"issued_at":{"type":"integer","title":"Issued At"},"expires_at":{"type":"integer","title":"Expires At"}},"type":"object","required":["jti","token","sub","scopes","product_id","label","issued_at","expires_at"],"title":"IssueResponse"},"IssueTokenIn":{"properties":{"scopes":{"items":{"type":"string"},"type":"array","minItems":1,"title":"Scopes","description":"Scopes to grant (must be subset of tenant.scopes)"},"ttl_days":{"type":"integer","maximum":365.0,"minimum":1.0,"title":"Ttl Days","description":"Token lifetime in days (default 90)","default":90},"token_id":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Token Id","description":"Optional explicit jti (e.g. 'ci-bot'). Auto-generated when omitted."}},"type":"object","required":["scopes"],"title":"IssueTokenIn"},"IssueTokenOut":{"properties":{"token":{"type":"string","title":"Token"},"jti":{"type":"string","title":"Jti"},"expires_at":{"type":"integer","title":"Expires At"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"tenant_id":{"type":"string","title":"Tenant Id"}},"type":"object","required":["token","jti","expires_at","scopes","tenant_id"],"title":"IssueTokenOut"},"JobDetailOut":{"properties":{"job_id":{"type":"string","title":"Job Id"},"tenant":{"type":"string","title":"Tenant"},"status":{"type":"string","title":"Status"},"created_at":{"type":"number","title":"Created At"},"completed_at":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Completed At"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"webhook_delivered_at":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Webhook Delivered At"},"webhook_status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Webhook Status Code"},"webhook_retry_count":{"type":"integer","title":"Webhook Retry Count"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"},"progress":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Progress"},"result":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Result"}},"type":"object","required":["job_id","tenant","status","created_at","completed_at","webhook_url","webhook_delivered_at","webhook_status_code","webhook_retry_count","error","result"],"title":"JobDetailOut"},"JobOut":{"properties":{"job_id":{"type":"string","title":"Job Id"},"tenant":{"type":"string","title":"Tenant"},"status":{"type":"string","title":"Status"},"created_at":{"type":"number","title":"Created At"},"completed_at":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Completed At"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"webhook_delivered_at":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Webhook Delivered At"},"webhook_status_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Webhook Status Code"},"webhook_retry_count":{"type":"integer","title":"Webhook Retry Count"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}},"type":"object","required":["job_id","tenant","status","created_at","completed_at","webhook_url","webhook_delivered_at","webhook_status_code","webhook_retry_count","error"],"title":"JobOut"},"JobSubmitIn":{"properties":{"messages":{"items":{"additionalProperties":true,"type":"object"},"type":"array","minItems":1,"title":"Messages"},"webhook_url":{"anyOf":[{"type":"string","maxLength":2083,"minLength":1,"format":"uri"},{"type":"null"}],"title":"Webhook Url","description":"If set, gateway POSTs result here when done (HMAC signed)."},"webhook_secret":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Secret","description":"Shared secret for HMAC-SHA256 signature. Customer verifies via `X-Gateway-Signature` header on webhook callback."},"tenant_context":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Tenant Context"},"output_preference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Preference"},"knowledge_packs_override":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Knowledge Packs Override"},"output_schema_override":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output Schema Override"},"writer_model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Writer Model Override"},"editor_model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Editor Model Override"},"max_revisions":{"type":"integer","title":"Max Revisions","default":1},"use_fresh_think_fallback":{"type":"boolean","title":"Use Fresh Think Fallback","default":true},"editor_score_threshold":{"type":"integer","title":"Editor Score Threshold","default":70},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Backend tier for the judge step. 'standard' (default, free) | 'premium' (Gemini Flash) | 'frontier' (Claude Haiku) | 'auto' (insights-driven). PII-bearing prompts pin LOCAL."},"judge_tools":{"type":"boolean","title":"Judge Tools","default":false},"writer_grounding":{"type":"boolean","title":"Writer Grounding","default":false}},"type":"object","required":["messages"],"title":"JobSubmitIn","description":"Same fields as SmartApiRequest + webhook fields."},"KeyListResponse":{"properties":{"tenant":{"type":"string","title":"Tenant"},"count":{"type":"integer","title":"Count"},"keys":{"items":{"$ref":"#/components/schemas/KeyRow"},"type":"array","title":"Keys"}},"type":"object","required":["tenant","count","keys"],"title":"KeyListResponse"},"KeyRow":{"properties":{"jti":{"type":"string","title":"Jti"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"product_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Product Id"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"issued_at":{"type":"integer","title":"Issued At"},"expires_at":{"type":"integer","title":"Expires At"},"revoked":{"type":"boolean","title":"Revoked"}},"type":"object","required":["jti","scopes","product_id","label","issued_at","expires_at","revoked"],"title":"KeyRow"},"KnowledgePackRef":{"properties":{"pack_id":{"type":"string","title":"Pack Id"},"top_k":{"type":"integer","title":"Top K","default":5},"audience_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience Level"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"}},"type":"object","required":["pack_id"],"title":"KnowledgePackRef"},"KnowledgeQueryRequest":{"properties":{"pack_id":{"type":"string","title":"Pack Id"},"query":{"type":"string","title":"Query"},"top_k":{"type":"integer","maximum":20.0,"minimum":1.0,"title":"Top K","default":5},"audience_level":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience Level"},"language":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Language"},"section":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Section"}},"type":"object","required":["pack_id","query"],"title":"KnowledgeQueryRequest"},"ListKeysOut":{"properties":{"providers":{"items":{"$ref":"#/components/schemas/ProviderKeyInfo"},"type":"array","title":"Providers"}},"type":"object","required":["providers"],"title":"ListKeysOut"},"LoginIn":{"properties":{"id":{"type":"string","maxLength":64,"minLength":1,"title":"Id"},"password":{"type":"string","maxLength":256,"minLength":1,"title":"Password"}},"type":"object","required":["id","password"],"title":"LoginIn"},"LoginOut":{"properties":{"token":{"type":"string","title":"Token"},"token_type":{"type":"string","title":"Token Type","default":"bearer"},"expires_at":{"type":"integer","title":"Expires At"},"owner_id":{"type":"string","title":"Owner Id"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"}},"type":"object","required":["token","expires_at","owner_id","scopes"],"title":"LoginOut"},"LongformBody":{"properties":{"corpus_id":{"type":"string","title":"Corpus Id"},"instruction":{"type":"string","maxLength":4000,"minLength":1,"title":"Instruction"},"pii_mode":{"type":"string","title":"Pii Mode","default":"local_only"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model","description":"reduce/final model เมื่อ pii_mode != local_only"},"webhook_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Webhook Url"},"resume_job_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resume Job Id","description":"R3.1: ใส่ job_id เดิมเพื่อ resume — node ที่เสร็จแล้วคืนจาก dag-cache ฟรี (รันต่อจากจุดที่ค้าง)"}},"type":"object","required":["corpus_id","instruction"],"title":"LongformBody"},"PackAccessIn":{"properties":{"tenant_ids":{"items":{"type":"string"},"type":"array","maxItems":200,"minItems":1,"title":"Tenant Ids","description":"Tenant IDs to grant access to this (private) pack."}},"type":"object","required":["tenant_ids"],"title":"PackAccessIn"},"PackCreateIn":{"properties":{"pack_id":{"type":"string","maxLength":64,"minLength":3,"title":"Pack Id"},"version":{"type":"string","maxLength":32,"minLength":1,"title":"Version"},"curator":{"type":"string","maxLength":64,"minLength":1,"title":"Curator"},"languages":{"items":{"type":"string"},"type":"array","title":"Languages"},"description":{"type":"string","maxLength":4000,"title":"Description","default":""},"tags":{"items":{"type":"string"},"type":"array","title":"Tags"},"domain":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Domain"},"subjects":{"items":{"type":"string"},"type":"array","title":"Subjects"},"intent_applicable":{"items":{"type":"string"},"type":"array","title":"Intent Applicable"},"private":{"type":"boolean","title":"Private","description":"When True, only tenants explicitly granted access (via the access endpoint) can list or query this pack.","default":false}},"type":"object","required":["pack_id","version","curator"],"title":"PackCreateIn"},"PolishRequest":{"properties":{"text":{"type":"string","minLength":1,"title":"Text","description":"ข้อความไทยที่ต้องการให้ขัดเกลา"},"style":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style","description":"ระดับภาษา: formal | neutral | casual (default: neutral)"},"writer_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Writer Model","description":"Override writer model. Default: env-configured polish writer."},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Backend tier for the JUDGE step. 'standard' (default) = free shared cloud · 'premium' = Gemini 2.5 Flash (lower variance) · 'frontier' = Claude Haiku 4.5 (highest quality). PII-bearing prompts pin LOCAL regardless of tier."}},"type":"object","required":["text"],"title":"PolishRequest"},"PrefixStats":{"properties":{"tenant":{"type":"string","title":"Tenant"},"by_model":{"additionalProperties":{"items":{"$ref":"#/components/schemas/PrefixWindowStat"},"type":"array"},"type":"object","title":"By Model"},"interpretation":{"type":"string","title":"Interpretation"}},"type":"object","required":["tenant","by_model","interpretation"],"title":"PrefixStats"},"PrefixWindowStat":{"properties":{"window_chars":{"type":"integer","title":"Window Chars"},"hit_ratio_recent":{"type":"number","title":"Hit Ratio Recent"},"sample_size":{"type":"integer","title":"Sample Size"}},"type":"object","required":["window_chars","hit_ratio_recent","sample_size"],"title":"PrefixWindowStat"},"PrimaryMetric":{"properties":{"name":{"type":"string","title":"Name"},"mean":{"type":"number","title":"Mean"},"median":{"type":"number","title":"Median"},"stdev":{"type":"number","title":"Stdev"},"min":{"type":"number","title":"Min"},"max":{"type":"number","title":"Max"}},"type":"object","required":["name","mean","median","stdev","min","max"],"title":"PrimaryMetric"},"ProductRow":{"properties":{"product":{"type":"string","title":"Product"},"inflight":{"type":"integer","title":"Inflight"}},"type":"object","required":["product","inflight"],"title":"ProductRow"},"PromptSetIn":{"properties":{"value":{"type":"string","maxLength":20000,"minLength":1,"title":"Value","description":"New prompt body"},"note":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"title":"Note","description":"Free-form note attached to this version (audit only)"}},"type":"object","required":["value"],"title":"PromptSetIn"},"ProviderKeyInfo":{"properties":{"provider":{"type":"string","title":"Provider"},"label":{"type":"string","title":"Label"},"env_var":{"type":"string","title":"Env Var"},"revoke_url":{"type":"string","title":"Revoke Url"},"has_key":{"type":"boolean","title":"Has Key"},"length":{"type":"integer","title":"Length"},"last4":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last4"}},"type":"object","required":["provider","label","env_var","revoke_url","has_key","length","last4"],"title":"ProviderKeyInfo"},"QueryBody":{"properties":{"query":{"type":"string","maxLength":2000,"minLength":1,"title":"Query"},"top_k":{"type":"integer","maximum":50.0,"minimum":1.0,"title":"Top K","default":8}},"type":"object","required":["query"],"title":"QueryBody"},"RateLimitIn":{"properties":{"per_minute":{"type":"integer","title":"Per Minute","default":200},"per_hour":{"type":"integer","title":"Per Hour","default":5000},"per_day":{"type":"integer","title":"Per Day","default":100000}},"type":"object","title":"RateLimitIn"},"ReadUrlRequest":{"properties":{"url":{"type":"string","title":"Url"},"max_chars":{"type":"integer","title":"Max Chars","default":8000}},"type":"object","required":["url"],"title":"ReadUrlRequest"},"ResearchBody":{"properties":{"question":{"type":"string","maxLength":4000,"minLength":1,"title":"Question"},"corpus_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Corpus Id"},"packs":{"anyOf":[{"items":{"type":"string"},"type":"array","maxItems":5},{"type":"null"}],"title":"Packs","description":"knowledge pack ids ที่อนุญาตให้ค้น"},"pii_mode":{"type":"string","title":"Pii Mode","default":"local_only"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"max_hops":{"type":"integer","maximum":12.0,"minimum":1.0,"title":"Max Hops","default":6},"top_k":{"type":"integer","maximum":20.0,"minimum":1.0,"title":"Top K","default":6}},"type":"object","required":["question"],"title":"ResearchBody"},"RestoreBaselineBody":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Restore only this prompt; omit to restore ALL."}},"type":"object","title":"RestoreBaselineBody"},"RevokeResponse":{"properties":{"jti":{"type":"string","title":"Jti"},"revoked":{"type":"boolean","title":"Revoked"},"already_revoked":{"type":"boolean","title":"Already Revoked"}},"type":"object","required":["jti","revoked","already_revoked"],"title":"RevokeResponse"},"ScheduleBody":{"properties":{"corpus_id":{"type":"string","title":"Corpus Id"},"instruction":{"type":"string","maxLength":4000,"minLength":1,"title":"Instruction"},"pii_mode":{"type":"string","title":"Pii Mode","default":"local_only"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"every_hours":{"type":"number","maximum":720.0,"minimum":0.1,"title":"Every Hours"}},"type":"object","required":["corpus_id","instruction","every_hours"],"title":"ScheduleBody"},"SetKeyIn":{"properties":{"new_key":{"type":"string","maxLength":512,"minLength":1,"title":"New Key"}},"type":"object","required":["new_key"],"title":"SetKeyIn"},"SetKeyOut":{"properties":{"provider":{"type":"string","title":"Provider"},"label":{"type":"string","title":"Label"},"last4":{"type":"string","title":"Last4"},"length":{"type":"integer","title":"Length"},"validated":{"type":"boolean","title":"Validated"},"validation_message":{"type":"string","title":"Validation Message"},"revoke_url":{"type":"string","title":"Revoke Url"},"next_step":{"type":"string","title":"Next Step"}},"type":"object","required":["provider","label","last4","length","validated","validation_message","revoke_url","next_step"],"title":"SetKeyOut"},"ShadowSetIn":{"properties":{"value":{"type":"string","maxLength":20000,"minLength":1,"title":"Value","description":"Candidate prompt body to mirror against"},"sample_pct":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Sample Pct","description":"Fraction of traffic to mirror (0.0-1.0). 0.05 = 5%. Background runs don't affect customer latency.","default":0.05},"note":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"title":"Note"}},"type":"object","required":["value"],"title":"ShadowSetIn"},"ShortenRequest":{"properties":{"text":{"type":"string","minLength":1,"title":"Text","description":"ข้อความต้นฉบับ"},"target_chars":{"anyOf":[{"type":"integer","maximum":10000.0,"minimum":20.0},{"type":"null"}],"title":"Target Chars","description":"Target character count for the shortened version. The model treats it as guidance not a hard cap. Default: ~30% of original length."},"style":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style","description":"ระดับภาษา: formal | neutral | casual (default: neutral)"},"writer_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Writer Model","description":"Override writer model. Default: WIZARD_POLISH_WRITER."},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Backend tier for judge. 'standard' | 'premium' | 'frontier'. PII pins LOCAL."}},"type":"object","required":["text"],"title":"ShortenRequest"},"SlaConfigResponse":{"properties":{"tenant":{"type":"string","title":"Tenant"},"sla_credit_enabled":{"type":"boolean","title":"Sla Credit Enabled"},"sla_credit_note":{"type":"string","title":"Sla Credit Note"},"explanation":{"type":"string","title":"Explanation"}},"type":"object","required":["tenant","sla_credit_enabled","sla_credit_note","explanation"],"title":"SlaConfigResponse"},"SlaConfigUpdate":{"properties":{"enabled":{"type":"boolean","title":"Enabled","description":"True turns on auto-credit calculation for this tenant. False (default) means the calculator skips this tenant — appropriate for on-prem appliance + pre-contract pilot deployments."},"note":{"type":"string","maxLength":200,"title":"Note","description":"Free-text: 'On-prem appliance v1', 'Pilot pre-contract', 'SaaS contract starting 2026-08-01', etc.","default":""}},"type":"object","required":["enabled"],"title":"SlaConfigUpdate"},"SmartApiRequest":{"properties":{"messages":{"items":{"$ref":"#/components/schemas/ComposeMessage"},"type":"array","minItems":1,"title":"Messages","description":"Must contain at least one message. Empty array rejected with 422."},"tenant_context":{"anyOf":[{"$ref":"#/components/schemas/SmartTenantContext"},{"type":"null"}]},"output_preference":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Output Preference"},"knowledge_packs_override":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Knowledge Packs Override"},"output_schema_override":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Output Schema Override"},"writer_model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Writer Model Override"},"editor_model_override":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Editor Model Override"},"max_revisions":{"type":"integer","title":"Max Revisions","default":1},"use_fresh_think_fallback":{"type":"boolean","title":"Use Fresh Think Fallback","default":true},"editor_score_threshold":{"type":"integer","title":"Editor Score Threshold","default":70},"skip_judge":{"type":"boolean","title":"Skip Judge","default":false},"max_cost_usd":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Cost Usd"},"thread_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Thread Id"},"thread_history_turns":{"type":"integer","title":"Thread History Turns","default":10},"self_critique":{"type":"boolean","title":"Self Critique","default":false},"multi_step_planning":{"type":"boolean","title":"Multi Step Planning","default":false},"stream":{"type":"boolean","title":"Stream","default":false},"stream_tokens":{"type":"boolean","title":"Stream Tokens","default":false},"task_category":{"type":"string","title":"Task Category","default":"auto"},"judge_tools":{"type":"boolean","title":"Judge Tools","default":false},"writer_grounding":{"type":"boolean","title":"Writer Grounding","default":false},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Backend tier for the JUDGE step. One of: 'standard' | 'premium' | 'frontier' | 'auto'. Default 'standard'. PII-bearing prompts are pinned LOCAL regardless of tier."}},"type":"object","required":["messages"],"title":"SmartApiRequest"},"SmartTenantContext":{"properties":{"sector":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sector"},"locale":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Locale"}},"type":"object","title":"SmartTenantContext"},"StartResearchIn":{"properties":{"pack_id":{"type":"string","maxLength":64,"minLength":3,"title":"Pack Id"},"domain":{"type":"string","maxLength":64,"minLength":2,"title":"Domain","description":"Whitelist key. Must exist in SOURCE_WHITELIST. Known: ['ai-governance', 'anti-corruption', 'civil-servant-development', 'cybersecurity', 'finance-esg', 'occupational-safety', 'pdpa', 'quality-iso', 'sme-operations']"},"audience_hint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Audience Hint"},"language":{"type":"string","title":"Language","default":"th"},"topics":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Topics","description":"OPTIONAL — supply a hand-written outline to skip the planner. Each item: {slug, title, question, audience_levels?}. If omitted, planner LLM generates the outline."},"notes":{"anyOf":[{"type":"string","maxLength":400},{"type":"null"}],"title":"Notes"},"corroboration":{"type":"integer","maximum":5.0,"minimum":1.0,"title":"Corroboration","description":"Minimum trusted sources required per topic. Lower to 1 when one official source is canonical (e.g. pdpc.or.th for PDPA control text). Default 2.","default":2}},"type":"object","required":["pack_id","domain"],"title":"StartResearchIn"},"TenantCreateIn":{"properties":{"tenant_id":{"type":"string","maxLength":64,"minLength":1,"title":"Tenant Id"},"name":{"type":"string","title":"Name","default":""},"contact":{"type":"string","title":"Contact","default":""},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes","default":[]},"allowed_ips":{"items":{"type":"string"},"type":"array","title":"Allowed Ips","default":[]},"allowed_models":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Models"},"rate_limit":{"anyOf":[{"$ref":"#/components/schemas/RateLimitIn"},{"type":"null"}]},"default_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Tier","description":"Default tier when a request omits `tier`. One of: 'standard' | 'premium' | 'frontier' | 'auto'. None → 'standard' at runtime."},"allowed_tiers":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Tiers","description":"Whitelist of tiers this tenant may request. None → all four. A buggy client requesting a non-whitelisted tier is silently downgraded to default_tier (still observable via X-Gateway-Tier-Downgraded-Reason header)."},"pdpa_allow_offshore_low":{"type":"boolean","title":"Pdpa Allow Offshore Low","description":"Tenant policy: allow LOW-risk PII (e.g. email-only) to be processed by offshore writers/judges. Default True. Set False for strict tenants who want EVERYTHING in-country.","default":true},"pdpa_allow_offshore_medium":{"type":"boolean","title":"Pdpa Allow Offshore Medium","description":"Tenant policy: allow MEDIUM-risk PII (personal name + context) to be processed offshore. Default False — most tenants will want this off. HIGH/SPECIAL are hard-locked regardless of this flag.","default":false},"pdpa_enforce":{"type":"boolean","title":"Pdpa Enforce","description":"Master switch for PDPA/PII enforcement on this tenant. Default False: the gateway classifies PII for audit but does NOT block any request. Set True for tenants under PDPA/HIPAA/GDPR — 451 blocks then activate using the pdpa_allow_offshore_* knobs above.","default":false},"compliance_mode":{"type":"string","title":"Compliance Mode","description":"Regulatory mode. 'off' = no enforcement (default). 'pdpa' | 'hipaa' | 'gdpr' all activate PDPA-style hard-local enforcement. Takes precedence over the deprecated pdpa_enforce bool.","default":"off"}},"type":"object","required":["tenant_id"],"title":"TenantCreateIn"},"TenantOut":{"properties":{"id":{"type":"string","title":"Id"},"name":{"type":"string","title":"Name"},"contact":{"type":"string","title":"Contact"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"allowed_ips":{"items":{"type":"string"},"type":"array","title":"Allowed Ips"},"allowed_models":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Models"},"rate_limit":{"$ref":"#/components/schemas/RateLimitIn"},"default_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Tier"},"allowed_tiers":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Tiers"},"pdpa_allow_offshore_low":{"type":"boolean","title":"Pdpa Allow Offshore Low","default":true},"pdpa_allow_offshore_medium":{"type":"boolean","title":"Pdpa Allow Offshore Medium","default":false},"pdpa_enforce":{"type":"boolean","title":"Pdpa Enforce","default":false},"compliance_mode":{"type":"string","title":"Compliance Mode","default":"off"}},"type":"object","required":["id","name","contact","scopes","allowed_ips","allowed_models","rate_limit"],"title":"TenantOut"},"TenantProductsResponse":{"properties":{"tenant":{"type":"string","title":"Tenant"},"overall_inflight":{"type":"integer","title":"Overall Inflight"},"products":{"items":{"$ref":"#/components/schemas/ProductRow"},"type":"array","title":"Products"}},"type":"object","required":["tenant","overall_inflight","products"],"title":"TenantProductsResponse"},"TenantUpdateIn":{"properties":{"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"contact":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Contact"},"scopes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Scopes"},"allowed_ips":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Ips"},"allowed_models":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Models"},"rate_limit":{"anyOf":[{"$ref":"#/components/schemas/RateLimitIn"},{"type":"null"}]},"default_tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Default Tier"},"allowed_tiers":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Tiers"},"pdpa_allow_offshore_low":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Pdpa Allow Offshore Low"},"pdpa_allow_offshore_medium":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Pdpa Allow Offshore Medium"},"pdpa_enforce":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Pdpa Enforce"},"compliance_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Compliance Mode"}},"type":"object","title":"TenantUpdateIn"},"TranslateThRequest":{"properties":{"text":{"type":"string","minLength":1,"title":"Text","description":"ข้อความต้นฉบับ (ภาษาใดก็ได้)"},"source_lang":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source Lang","description":"Source language hint (e.g. 'en', 'ja', 'zh'). Optional — Typhoon autodetects. Pass when the input is short or ambiguous to nudge the model."},"style":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Style","description":"ระดับภาษา: formal | neutral | casual (default: neutral)"},"writer_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Writer Model","description":"Override writer model. Default: WIZARD_POLISH_WRITER."},"tier":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tier","description":"Backend tier for the judge step. 'standard' (default) | 'premium' (Gemini Flash) | 'frontier' (Claude Haiku). PII pins LOCAL regardless of tier."}},"type":"object","required":["text"],"title":"TranslateThRequest"},"ValidateIdIn":{"properties":{"id":{"type":"string","title":"Id"}},"type":"object","required":["id"],"title":"ValidateIdIn"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VersionIn":{"properties":{"version":{"type":"string","maxLength":32,"minLength":1,"title":"Version"}},"type":"object","required":["version"],"title":"VersionIn"},"VisualizationHint":{"properties":{"type":{"type":"string","enum":["histogram","bar","scatter","boxplot"],"title":"Type"},"title":{"type":"string","title":"Title"},"column":{"type":"string","title":"Column"},"secondary_column":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Secondary Column"}},"type":"object","required":["type","title","column"],"title":"VisualizationHint"},"WebSearchRequest":{"properties":{"query":{"type":"string","title":"Query"},"n":{"type":"integer","title":"N","default":6}},"type":"object","required":["query"],"title":"WebSearchRequest"},"WhitelistIn":{"properties":{"sources":{"items":{"type":"string"},"type":"array","maxItems":50,"minItems":1,"title":"Sources"}},"type":"object","required":["sources"],"title":"WhitelistIn"},"_BreakerOpenBody":{"properties":{"cooldown_s":{"anyOf":[{"type":"number","maximum":3600.0,"minimum":1.0},{"type":"null"}],"title":"Cooldown S","description":"If set, override the cooldown window for this trip."}},"type":"object","title":"_BreakerOpenBody"},"_LimitBody":{"properties":{"limit":{"anyOf":[{"type":"integer","maximum":1024.0,"minimum":1.0},{"type":"null"}],"title":"Limit"},"queue_size":{"anyOf":[{"type":"integer","maximum":1024.0,"minimum":0.0},{"type":"null"}],"title":"Queue Size"},"actor":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}],"title":"Actor"}},"type":"object","title":"_LimitBody"}},"securitySchemes":{"BearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"JWT bearer token (production) or demo bearer (sandbox)."}}},"tags":[{"name":"Chat & Completions","description":"OpenAI-compat chat — streaming (SSE) + function calling + JSON mode + structured content + cache_control passthrough"},{"name":"Wizard","description":"Pre-built presets over the Smart Engine — one-call utilities (Thai polish, fact-check, grounded summarize). No prompt+glue to write."},{"name":"Grounding","description":"Real-world data tools the engine and any caller can use — `web_search` (SearXNG, Thai-first), `read_url` (HTML/PDF + SSRF guard + Thai ำ-repair). Anti-fabrication primitive."},{"name":"Knowledge","description":"Curated knowledge packs + flywheel — query curated chunks, draft new chunks from real URLs, admin-review, approve into `sources/` + auto re-embed."},{"name":"Embeddings","description":"OpenAI-compat embeddings — in-country `nomic-embed-text` (768-dim) + Thai-tuned `gateway-embed-th` (BGE-M3, 1024-dim)"},{"name":"Catalog","description":"Model discovery + smart routing aliases (`gateway-th`, `local-writer-th`, `local-analyst-th`, ...)"},{"name":"Audit & Transparency","description":"Per-request compliance evidence — proof of HARD RULE #3 (no raw PII in logs)"},{"name":"Demo Tasks","description":"Higher-level orchestration examples (exam, cohort, csv-analyze). NOT product features — keep as reference"},{"name":"Admin","description":"Owner / admin endpoints — tenants, knowledge flywheel review, audit, cost. Requires admin-tenant bearer."},{"name":"Health","description":"Liveness + backend probes — no auth"}],"security":[{"BearerAuth":[]}]}