{"openapi":"3.1.0","info":{"title":"INZARA Management API","version":"v1","description":"The workspace-scoped management API for INZARA embedded analytics. Issue embed session JWTs, provision workspaces, read usage metering, and manage API keys. See https://github.com/emergent/inzara for hosted playbooks."},"paths":{"/api/mgmt/v1/api-keys":{"post":{"summary":"Create Api Key Endpoint","description":"Mint a new mgmt API key. Retry-safe via `Idempotency-Key` header —\nsame key + same body inside 24h returns the same secret (letting\nhosts safely retry a network hiccup without duplicating keys).","operationId":"create_api_key_endpoint_api_mgmt_v1_api_keys_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateApiKeyIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List Api Keys Endpoint","description":"Cursor-paginated list of mgmt API keys for the caller's tenant.\n\nQuery params:\n  - `cursor` — opaque; pass `next_cursor` from previous page\n  - `limit`  — 1..200, default 50\n\nResponse: `{\"data\": [...], \"next_cursor\": \"…\" | null}`.\nBcrypt hashes are stripped server-side and never returned.","operationId":"list_api_keys_endpoint_api_mgmt_v1_api_keys_get","parameters":[{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/api-keys/{key_id}":{"delete":{"summary":"Revoke Api Key Endpoint","operationId":"revoke_api_key_endpoint_api_mgmt_v1_api_keys__key_id__delete","parameters":[{"name":"key_id","in":"path","required":true,"schema":{"type":"string","title":"Key Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/scopes":{"get":{"summary":"List Scopes Endpoint","description":"Reference — what scopes can be granted. Useful in admin UI.","operationId":"list_scopes_endpoint_api_mgmt_v1_scopes_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mgmt/v1/workspaces":{"post":{"summary":"Create Workspace Endpoint","description":"Provision a new workspace. Retry-safe via `Idempotency-Key`\nheader — same key + same body inside 24h returns the same workspace\n(so a network hiccup doesn't fork duplicate workspace rows with the\nsame slug).","operationId":"create_workspace_endpoint_api_mgmt_v1_workspaces_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateWorkspaceIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List Workspaces Endpoint","description":"Cursor-paginated list of workspaces in the caller's tenant.\n\nQuery params:\n  - `cursor` (opaque): pass the `next_cursor` from the previous\n    page. Omit on the first call.\n  - `limit`  (int, 1..200; default 50): rows per page.\n\nResponse: `{\"data\": [...], \"next_cursor\": \"…\" | null}`.\n`next_cursor === null` means you've reached the end.","operationId":"list_workspaces_endpoint_api_mgmt_v1_workspaces_get","parameters":[{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}":{"get":{"summary":"Get Workspace Endpoint","operationId":"get_workspace_endpoint_api_mgmt_v1_workspaces__workspace_id__get","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"summary":"Update Workspace Endpoint","operationId":"update_workspace_endpoint_api_mgmt_v1_workspaces__workspace_id__patch","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkspaceIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Delete Workspace Endpoint","operationId":"delete_workspace_endpoint_api_mgmt_v1_workspaces__workspace_id__delete","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/branding":{"get":{"summary":"Get Workspace Branding Endpoint","description":"Return the effective branding for a workspace. Missing keys are\nfilled with defaults; `product_name` falls back to the workspace name.","operationId":"get_workspace_branding_endpoint_api_mgmt_v1_workspaces__workspace_id__branding_get","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Update Workspace Branding Endpoint","description":"Merge-patch a workspace's white-label branding (logo, colors,\nproduct name). All values validated server-side; unknown keys are\nrejected by the schema (`extra=\"forbid\"`).","operationId":"update_workspace_branding_endpoint_api_mgmt_v1_workspaces__workspace_id__branding_put","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceBrandingIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/custom-domain":{"get":{"summary":"Get Workspace Custom Domain Endpoint","description":"Return the current custom-domain state — domain, verification\nstatus, and DNS instructions if unverified.","operationId":"get_workspace_custom_domain_endpoint_api_mgmt_v1_workspaces__workspace_id__custom_domain_get","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Set Workspace Custom Domain Endpoint","description":"Assign or clear a workspace's custom domain. Assignment issues a\nfresh TXT challenge; the caller must then create the DNS records\nand call `.../custom-domain/verify` before hosts start resolving.","operationId":"set_workspace_custom_domain_endpoint_api_mgmt_v1_workspaces__workspace_id__custom_domain_put","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CustomDomainIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/custom-domain/verify":{"post":{"summary":"Verify Workspace Custom Domain Endpoint","description":"Look up the DNS TXT record and flip `verified_at` if it matches\nthe current challenge. Idempotent — safe to poll.","operationId":"verify_workspace_custom_domain_endpoint_api_mgmt_v1_workspaces__workspace_id__custom_domain_verify_post","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/platform/verified-domains":{"get":{"summary":"List Verified Domains Endpoint","description":"Return every verified custom domain across the whole cluster.\nDeploy tools consume this to keep the ingress config in sync.","operationId":"list_verified_domains_endpoint_api_mgmt_v1_platform_verified_domains_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mgmt/v1/platform/ingress-manifest":{"get":{"summary":"Emit Ingress Manifest Endpoint","description":"Return the k8s Ingress + Certificate manifest bundle covering\nall currently-verified domains. `kubectl apply -f -` friendly.\nEmpty verified list → empty body (idempotent no-op).","operationId":"emit_ingress_manifest_endpoint_api_mgmt_v1_platform_ingress_manifest_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mgmt/v1/platform/ingress-sync":{"post":{"summary":"Ingress Sync Endpoint","description":"Regenerate the ingress manifest and persist its hash so ops\ntooling can detect drift with a single request. Returns\n`{status: 'synced' | 'noop', hash, domain_count, hosts[], changed}`.\n\nDesigned for cron-driven pipelines — POST every minute; when\n`changed` flips to True, the caller pipes\n`GET /platform/ingress-manifest` into `kubectl apply -f -`.\nRequires `platform:write`.","operationId":"ingress_sync_endpoint_api_mgmt_v1_platform_ingress_sync_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mgmt/v1/platform/ingress-state":{"get":{"summary":"Ingress State Endpoint","description":"Return the last synced ingress state (hash + host list +\nupdated_at). Callers poll this cheaply to decide whether to\ntrigger a fresh `apply`. Requires `platform:read`.","operationId":"ingress_state_endpoint_api_mgmt_v1_platform_ingress_state_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/starter-questions":{"get":{"summary":"Get Starter Questions Endpoint","description":"List the workspace's Explore starter questions.","operationId":"get_starter_questions_endpoint_api_mgmt_v1_workspaces__workspace_id__starter_questions_get","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Put Starter Questions Endpoint","description":"Bulk-replace the workspace's Explore starter question set.\nDeletes the previous rows and inserts the new ordered list.\nIdempotent — safe to call from a config-sync job.","operationId":"put_starter_questions_endpoint_api_mgmt_v1_workspaces__workspace_id__starter_questions_put","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StarterQuestionsIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/history-retention":{"get":{"summary":"Get Workspace History Retention Endpoint","description":"Return the effective per-dashboard save-history retention cap\nfor this workspace. Falls back to the platform default (20) when\nthe workspace has never been tuned.","operationId":"get_workspace_history_retention_endpoint_api_mgmt_v1_workspaces__workspace_id__history_retention_get","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"put":{"summary":"Set Workspace History Retention Endpoint","description":"Tune per-dashboard save-history retention (1-200). New value\napplies to subsequent saves; already-pruned snapshots don't come\nback, but existing rows beyond the cap will be pruned on the next\nsave.","operationId":"set_workspace_history_retention_endpoint_api_mgmt_v1_workspaces__workspace_id__history_retention_put","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoryRetentionIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/layout-presets":{"get":{"summary":"List Workspace Presets Endpoint","description":"List custom layout presets defined for this workspace.","operationId":"list_workspace_presets_endpoint_api_mgmt_v1_workspaces__workspace_id__layout_presets_get","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"summary":"Create Workspace Preset Endpoint","description":"Create a custom layout preset for this workspace.\n\n`widgets[]` accepts entries with `widget_type`, `title`, `x`, `y`,\n`w`, `h`, `config`. Bounds are clamped server-side (max 12 cols,\nmax 30 rows tall per tile) so a malformed template can't produce\na broken canvas.","operationId":"create_workspace_preset_endpoint_api_mgmt_v1_workspaces__workspace_id__layout_presets_post","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LayoutPresetIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/layout-presets/{preset_id}":{"delete":{"summary":"Delete Workspace Preset Endpoint","operationId":"delete_workspace_preset_endpoint_api_mgmt_v1_workspaces__workspace_id__layout_presets__preset_id__delete","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}},{"name":"preset_id","in":"path","required":true,"schema":{"type":"string","title":"Preset Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/users":{"post":{"summary":"Upsert Workspace User Endpoint","operationId":"upsert_workspace_user_endpoint_api_mgmt_v1_workspaces__workspace_id__users_post","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpsertWorkspaceUserIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List Workspace Users Endpoint","operationId":"list_workspace_users_endpoint_api_mgmt_v1_workspaces__workspace_id__users_get","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/users/{sub}":{"patch":{"summary":"Update Workspace User Endpoint","operationId":"update_workspace_user_endpoint_api_mgmt_v1_workspaces__workspace_id__users__sub__patch","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}},{"name":"sub","in":"path","required":true,"schema":{"type":"string","title":"Sub"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateWorkspaceUserIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"summary":"Revoke Workspace User Endpoint","operationId":"revoke_workspace_user_endpoint_api_mgmt_v1_workspaces__workspace_id__users__sub__delete","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}},{"name":"sub","in":"path","required":true,"schema":{"type":"string","title":"Sub"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/workspaces/{workspace_id}/users/{sub}/budget":{"put":{"summary":"Set User Budget Endpoint","operationId":"set_user_budget_endpoint_api_mgmt_v1_workspaces__workspace_id__users__sub__budget_put","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}},{"name":"sub","in":"path","required":true,"schema":{"type":"string","title":"Sub"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetUserBudgetIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"Get User Budget Status Endpoint","description":"Return today's remaining budget for a user. Useful for hosts to\nsurface \"$X of $Y used today\" in their own UI.\n\nResponse:\n  {\n    \"workspace_id\": ..., \"sub\": ...,\n    \"ai\":            { \"cap_usd\": 5.0, \"spent_usd\": 1.2, \"remaining_usd\": 3.8 },\n    \"investigation\": { \"cap_usd\": 3.0, \"spent_usd\": 0.0, \"remaining_usd\": 3.0 }\n  }","operationId":"get_user_budget_status_endpoint_api_mgmt_v1_workspaces__workspace_id__users__sub__budget_get","parameters":[{"name":"workspace_id","in":"path","required":true,"schema":{"type":"string","title":"Workspace Id"}},{"name":"sub","in":"path","required":true,"schema":{"type":"string","title":"Sub"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/embed/sessions":{"post":{"summary":"Mint Embed Session Endpoint","description":"Mint a short-lived embed viewer JWT for a host end-user.\n\nHost calls this from their backend, then hands the returned `token`\nto the iframe / SDK. Never expose the mgmt API key to the browser.\n\nIdempotency\n-----------\nPass an `Idempotency-Key` header (any opaque string ≤ 255 chars) to\nmake the mint safe to retry. Identical `(tenant_id, \"embed.mint\",\nkey)` calls with the same body return the *same* token for 24 h;\nsame key with a different body returns `409 idempotency_conflict`.\nNetwork retries, container restarts, and edge-function double-fires\nstop duplicating JWTs and `embed_sessions` rows.","operationId":"mint_embed_session_endpoint_api_mgmt_v1_embed_sessions_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MintEmbedSessionIn"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"get":{"summary":"List Embed Sessions Endpoint","description":"Cursor-paginated list of embed sessions for observability + revocation UX.\nNever returns the JWTs themselves — those are only revealed at mint time.\n\nQuery params (all optional):\n  - `workspace_id`, `sub`, `active_only` — filters\n  - `cursor` — opaque; pass `next_cursor` from previous page\n  - `limit` — 1..500, default 50 (cap higher than the workspace list\n    because operators frequently spelunk through session logs)\n\nResponse: `{\"data\": [...], \"next_cursor\": \"…\" | null}`","operationId":"list_embed_sessions_endpoint_api_mgmt_v1_embed_sessions_get","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Id"}},{"name":"sub","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sub"}},{"name":"active_only","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Active Only"}},{"name":"cursor","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cursor"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/embed/sessions/revoke":{"post":{"summary":"Revoke Embed Session Endpoint","operationId":"revoke_embed_session_endpoint_api_mgmt_v1_embed_sessions_revoke_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevokeEmbedSessionIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/embed/sessions/verify":{"post":{"summary":"Verify Embed Session Endpoint","description":"Server-side helper — validate a JWT and return its claims.\n\nUseful for hosts to sanity-check a session in tests without spinning\nup an actual iframe. Also returns a normalised set of claims the\nembed viewer will see.","operationId":"verify_embed_session_endpoint_api_mgmt_v1_embed_sessions_verify_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyEmbedTokenIn"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/usage/query-events":{"get":{"summary":"List Query Events Endpoint","description":"List raw query events (30-day TTL). Prefer /usage for aggregated\nbilling views — this endpoint is useful for debugging + drill-down.","operationId":"list_query_events_endpoint_api_mgmt_v1_usage_query_events_get","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Id"}},{"name":"sub","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sub"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":100,"title":"Limit"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/usage":{"get":{"summary":"Usage Daily Endpoint","description":"Aggregated daily rollups suitable for billing exports.\nQuery params `from_day` / `to_day` are inclusive YYYY-MM-DD strings.","operationId":"usage_daily_endpoint_api_mgmt_v1_usage_get","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Id"}},{"name":"from_day","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"From Day"}},{"name":"to_day","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"To Day"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/usage/current-month":{"get":{"summary":"Current Month Usage Endpoint","description":"Aggregated usage for the current UTC month, per workspace.\n\nPowers host-side \"your embed usage is $X this month\" billing tiles.\nReads directly from `query_usage_daily` rollups so responses stay\nconstant-time regardless of raw event volume. p95/p99 latency\npercentiles are computed from raw `query_events` for the month —\nscanned in a small window so this stays cheap.\n\nResponse shape:\n  {\n    \"period\":       { \"from\": \"2026-02-01\", \"to\": \"2026-02-29\" },\n    \"total\": {\n      \"queries\":               <int>,\n      \"ai_queries\":            <int>,\n      \"cache_hits\":            <int>,\n      \"cost_estimate_usd\":     <float>,\n      \"ms_total\":              <int>,\n      \"avg_ms_per_query\":      <float>,\n      \"p95_ms\":                <int>,   # from raw events window\n      \"unique_subs\":           <int>,\n    },\n    \"by_workspace\": [\n      { workspace_id, name, queries, cost_estimate_usd,\n        ai_queries, cache_hits, unique_subs }\n      ...\n    ]\n  }","operationId":"current_month_usage_endpoint_api_mgmt_v1_usage_current_month_get","parameters":[{"name":"workspace_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Workspace Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/mgmt/v1/usage/digest/preview":{"get":{"summary":"Usage Weekly Digest Preview","description":"Return the JSON preview of this tenant's weekly usage digest —\nexactly what a Monday-morning cron would email out. Framework-free\npayload includes `subject`, `body_text`, per-workspace breakdown,\nand week-over-week deltas. Requires `usage:read` scope.\n\nHosts typically wire this into their own SendGrid/Resend/SES cron:\nfetch this endpoint every Monday 09:00 in the tenant's timezone,\nthen POST the returned `subject` + `body_text` to their email\nprovider.","operationId":"usage_weekly_digest_preview_api_mgmt_v1_usage_digest_preview_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mgmt/v1/status":{"get":{"summary":"Mgmt Status","description":"Heartbeat + self-test for mgmt API clients.\n\nAnswers three questions in one curl:\n  1. Is my key working? (200 + auth resolved)\n  2. Am I within my rate-limit budget? (the standard\n     `X-RateLimit-*` headers are attached by the middleware)\n  3. What version / scope am I operating against?\n\nRequires *any* valid mgmt authentication — no dedicated scope, so a\nkey can prove liveness even after its usage:read/workspaces:read\nscope has been rotated off.","operationId":"mgmt_status_api_mgmt_v1_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mgmt/v1/openapi.json":{"get":{"summary":"Mgmt Openapi Spec","description":"The **frozen** OpenAPI spec for every `/api/mgmt/v1/*` route.\n\nPublicly readable — no mgmt-key auth required. Hosts building typed\nNode/Python/Go/Rust clients can point their codegen (openapi-generator,\norval, oapi-codegen, etc.) at this URL and get a fully typed SDK for\nfree. The exact same JSON is committed at\n`/app/sdk/openapi/mgmt_openapi_v1.json` and validated by\n`tests/test_p1_mgmt_openapi_snapshot.py` so drift can't slip in\nsilently through a code review.","operationId":"mgmt_openapi_spec_api_mgmt_v1_openapi_json_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}},"/api/mgmt/v1/health":{"get":{"summary":"Platform Health Endpoint","description":"Compact real-time snapshot for the Platform Admin landing view.\n\nReturns:\n  {\n    active_workspaces:      count of non-deleted workspaces\n    active_api_keys:        count of non-revoked mgmt keys\n    budget_exhausted_24h:   number of rejections in last 24h\n    top_workspace_today:    {workspace_id, name, cost_usd} or null\n  }","operationId":"platform_health_endpoint_api_mgmt_v1_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}}}}}},"components":{"schemas":{"CreateApiKeyIn":{"properties":{"name":{"type":"string","maxLength":80,"title":"Name"},"env":{"type":"string","title":"Env","default":"live"},"scopes":{"items":{"type":"string"},"type":"array","title":"Scopes"},"expires_at":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["name"],"title":"CreateApiKeyIn"},"CreateWorkspaceIn":{"properties":{"name":{"type":"string","maxLength":120,"title":"Name"},"slug":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Slug"},"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes"},"settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Settings"}},"type":"object","required":["name"],"title":"CreateWorkspaceIn"},"CustomDomainIn":{"properties":{"domain":{"anyOf":[{"type":"string","maxLength":253},{"type":"null"}],"title":"Domain","description":"e.g. analytics.customer.com — null to clear"}},"type":"object","title":"CustomDomainIn","description":"Payload for setting a workspace's custom domain."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HistoryRetentionIn":{"properties":{"retention":{"type":"integer","maximum":200.0,"minimum":1.0,"title":"Retention","description":"Snapshots kept per dashboard (1-200)"}},"type":"object","required":["retention"],"title":"HistoryRetentionIn"},"LayoutPresetIn":{"properties":{"label":{"type":"string","maxLength":60,"minLength":1,"title":"Label"},"description":{"type":"string","maxLength":280,"title":"Description","default":""},"widgets":{"items":{},"type":"array","minItems":1,"title":"Widgets"}},"type":"object","required":["label","widgets"],"title":"LayoutPresetIn"},"MintEmbedSessionIn":{"properties":{"workspace_id":{"type":"string","maxLength":64,"title":"Workspace Id"},"sub":{"type":"string","maxLength":200,"title":"Sub"},"email":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Email"},"roles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Roles"},"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes"},"ai_budget_usd_daily":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ai Budget Usd Daily"},"investigation_budget_usd_daily":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Investigation Budget Usd Daily"},"resource":{"type":"string","title":"Resource","default":"dashboard"},"resource_id":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Resource Id"},"capabilities":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Capabilities"},"ttl_seconds":{"type":"integer","title":"Ttl Seconds","default":900}},"type":"object","required":["workspace_id","sub"],"title":"MintEmbedSessionIn"},"RevokeEmbedSessionIn":{"properties":{"jti":{"type":"string","maxLength":200,"title":"Jti"}},"type":"object","required":["jti"],"title":"RevokeEmbedSessionIn"},"SetUserBudgetIn":{"properties":{"ai_budget_usd_daily":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ai Budget Usd Daily"},"investigation_budget_usd_daily":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Investigation Budget Usd Daily"}},"type":"object","title":"SetUserBudgetIn"},"StarterQuestionsIn":{"properties":{"texts":{"items":{"type":"string"},"type":"array","maxItems":10,"title":"Texts","description":"Ordered list of starter prompt texts (max 10)"}},"type":"object","required":["texts"],"title":"StarterQuestionsIn"},"UpdateWorkspaceIn":{"properties":{"name":{"anyOf":[{"type":"string","maxLength":120},{"type":"null"}],"title":"Name"},"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes"},"settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Settings"},"branding_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Branding Id"}},"type":"object","title":"UpdateWorkspaceIn"},"UpdateWorkspaceUserIn":{"properties":{"roles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Roles"},"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes"},"ai_budget_usd_daily":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ai Budget Usd Daily"},"investigation_budget_usd_daily":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Investigation Budget Usd Daily"}},"type":"object","title":"UpdateWorkspaceUserIn"},"UpsertWorkspaceUserIn":{"properties":{"sub":{"type":"string","maxLength":200,"title":"Sub"},"email":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Email"},"roles":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Roles"},"attributes":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Attributes"},"ai_budget_usd_daily":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Ai Budget Usd Daily"},"investigation_budget_usd_daily":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Investigation Budget Usd Daily"}},"type":"object","required":["sub"],"title":"UpsertWorkspaceUserIn"},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifyEmbedTokenIn":{"properties":{"token":{"type":"string","title":"Token"}},"type":"object","required":["token"],"title":"VerifyEmbedTokenIn"},"WorkspaceBrandingIn":{"properties":{"logo_url":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Logo Url"},"favicon_url":{"anyOf":[{"type":"string","maxLength":2048},{"type":"null"}],"title":"Favicon Url"},"product_name":{"anyOf":[{"type":"string","maxLength":80},{"type":"null"}],"title":"Product Name"},"primary_color":{"anyOf":[{"type":"string","maxLength":9},{"type":"null"}],"title":"Primary Color"},"accent_color":{"anyOf":[{"type":"string","maxLength":9},{"type":"null"}],"title":"Accent Color"},"background_color":{"anyOf":[{"type":"string","maxLength":9},{"type":"null"}],"title":"Background Color"},"text_color":{"anyOf":[{"type":"string","maxLength":9},{"type":"null"}],"title":"Text Color"}},"additionalProperties":false,"type":"object","title":"WorkspaceBrandingIn","description":"Whitelist-only branding patch. Any field omitted is left untouched;\nan explicit `null` clears that field. Unknown keys → 422."}}}}