From 4841432501e0e07ca0ccf6ea358c2ff58c1b2dee Mon Sep 17 00:00:00 2001 From: Daniel Spangenberger Date: Fri, 5 Jun 2026 17:15:24 -0400 Subject: [PATCH 1/4] feat: add v2 documents commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sync the OpenAPI spec to pull in the v2 documents API, which is now GA — no experimental flags. These auto-generate as `omni documents v2-create`, `v2-get`, `v2-get-draft`, `v2-patch-draft`, `v2-patch-draft-by-identifier`, and `v2-publish-draft`. Upstream replaced the one-shot PATCH /api/v2/documents/{identifier} with the draft flow (patch a draft, then publish it) and added the create and publish routes. The spec is synced from the monorepo GA branch (dan/api-v2-documents-ga) ahead of its merge to main. Add body shorthands promoting metadata fields to flags: --name/--description/--summary on both draft PATCH commands plus --branch-id on v2-patch-draft, and positional with --identifier/--description/--folder-id on v2-create. Heavy nested content (containers, controls, queryPresentations, settings) stays on --body/stdin and round-trips cleanly from a v2-get response. Also document the v2 create/read/edit/publish workflow in agent-help. Side-effect operations pulled in by the full sync: a new `omni ai-eval` group (aiEvalPromptSets*), plus aiBranding, aiConversationDetail, aiConversationsList, connectionsDelete, connectionsGet, documentsListDrafts, documentsListFavorites, modelAiAgentActions. Co-Authored-By: Claude Fable 5 --- api/openapi.json | 36796 ++++++++++++++++++---- cmd/omni/agent_help.go | 18 + cmd/omni/openapi.json | 36796 ++++++++++++++++++---- internal/openapi/body_shorthand.go | 52 +- internal/openapi/body_shorthand_test.go | 102 +- 5 files changed, 60436 insertions(+), 13328 deletions(-) diff --git a/api/openapi.json b/api/openapi.json index b83fb7c..8697147 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -15,6 +15,10 @@ "description": "AI-powered data analysis. Submit natural language questions as synchronous queries or asynchronous jobs, and retrieve results including generated queries, data, and summarized answers.", "name": "AI" }, + { + "description": "AI evaluation: manage prompt sets and runs used to score AI quality against curated prompt suites.", + "name": "AI Eval" + }, { "description": "API token management", "name": "API Tokens" @@ -118,407 +122,559 @@ "description": "Update an existing variable by ID. Variable names cannot be changed after creation.", "title": "DbtEnvironmentVariableUpdate" }, - "AiGenerateQueryResponse": { + "CompositeFilter": { "type": "object", "properties": { - "error": { - "type": [ - "object", - "null" - ], - "properties": { - "detail": { - "type": "string", - "description": "Detailed error message explaining why query generation failed.", - "example": "The AI was unable to generate a query for this prompt. Try rephrasing your question to be more specific about the data you want to retrieve." - }, - "message": { - "type": "string", - "description": "Short error summary.", - "example": "No query generated" - } - }, - "required": [ - "detail", - "message" - ], - "description": "Error details if query generation failed. Null on success." - }, - "query": { - "$ref": "#/components/schemas/AiSemanticQuery" - }, - "result": { - "type": "object", - "additionalProperties": {}, - "description": "Query execution results as a JSON object. Only present when runQuery is true (the default) and the query executed successfully. The structure contains the query result data." + "cancel_query_filter": { + "type": "boolean" }, - "topic": { - "type": "string", - "description": "The topic name that was used for query generation.", - "example": "order_items" + "ignore_if_unjoinable": { + "type": "boolean" }, - "workbookUrl": { + "conjunction": { "type": "string", - "format": "uri", - "description": "URL to view and edit the generated query in an Omni workbook. Only present when workbookUrl was set to true in the request.", - "example": "https://myorg.omni.co/w/abc123/1" - } - }, - "required": [ - "error", - "query" - ] - }, - "AiSemanticQuery": { - "type": [ - "object", - "null" - ], - "properties": { - "fields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Ordered list of fully qualified field names to include in the query (e.g., \"view_name.field_name\").", - "example": [ - "products.name", - "order_items.total_revenue" + "enum": [ + "OR", + "AND" ] }, "filters": { - "type": "object", - "additionalProperties": {}, - "description": "Filter conditions keyed by fully qualified field name. Filter values vary by field type." - }, - "limit": { - "type": "integer", - "description": "Maximum number of rows to return.", - "example": 500 - }, - "sorts": { "type": "array", "items": { - "$ref": "#/components/schemas/AiQuerySort" - }, - "description": "Sort specifications applied to the query results." - }, - "table": { - "type": "string", - "description": "The base topic or view name for the query.", - "example": "order_items" - } - }, - "required": [ - "fields" - ], - "additionalProperties": {}, - "description": "The generated semantic query definition. Null if generation failed. This query can be passed directly to the POST /api/v1/query/run endpoint." - }, - "AiQuerySort": { - "type": "object", - "properties": { - "column_name": { - "type": "string", - "description": "Fully qualified field name to sort by (e.g., \"view_name.field_name\").", - "example": "order_items.total_revenue" - }, - "sort_descending": { - "type": "boolean", - "description": "Whether to sort in descending order.", - "example": true - } - }, - "required": [ - "column_name", - "sort_descending" - ] - }, - "ApiError400": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Bad Request: prompt: Required" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 400 - } - }, - "required": [ - "detail", - "status" - ] - }, - "ApiError401": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Unauthorized: Missing or invalid API key" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 401 - } - }, - "required": [ - "detail", - "status" - ] - }, - "ApiError403": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Forbidden: AI query generation is not enabled for this organization" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 403 - } - }, - "required": [ - "detail", - "status" - ] - }, - "ApiError404": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Model 770e8400-e29b-41d4-a716-446655440002 not found" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 404 - } - }, - "required": [ - "detail", - "status" - ] - }, - "AiGenerateQueryBody": { - "allOf": [ - { - "$ref": "#/components/schemas/AiTopicParams" - }, - { - "type": "object", - "properties": { - "prompt": { - "type": "string", - "description": "The natural language prompt describing the data you want to retrieve.", - "example": "Show me total revenue by month for the last year" - }, - "queryAllViews": { - "type": "boolean", - "description": "If true and the model has query_all_views_and_fields enabled, AI can query views not in any topic." - }, - "runQuery": { - "type": "boolean", - "description": "Whether to execute the generated query and return results. Defaults to true. Set to false to only generate the query definition without executing it.", - "example": true - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID to execute the query as. Their permissions will be applied for row-level security. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", - "example": "990e8400-e29b-41d4-a716-446655440004" - }, - "workbookUrl": { - "type": "boolean", - "description": "If true, creates a new workbook with the generated query and returns its URL. Useful for sharing results or further exploration.", - "example": false - } - }, - "required": [ - "prompt" - ] - } - ] - }, - "AiTopicParams": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "currentTopicName": { - "type": "string", - "description": "The name of the current topic to scope query generation. If not provided, AI will automatically select the best topic for your prompt.", - "example": "order_items" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the shared model to query against. Only shared models are supported.", - "example": "770e8400-e29b-41d4-a716-446655440002" - } - }, - "required": [ - "modelId" - ] - }, - "AiPickTopicResponse": { - "type": "object", - "properties": { - "topicId": { - "type": "string", - "description": "The name of the topic that best matches the prompt. Use this as the topicName parameter when calling generate-query or submitting an AI job.", - "example": "order_items" + "anyOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "kind", + "type", + "values" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + } + }, + "required": [ + "kind", + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + } + }, + "required": [ + "type", + "user_attribute_name" + ] + }, + { + "$ref": "#/components/schemas/CompositeFilter" + } + ] + }, + "description": "Child filters — each a simple filter or another composite filter. Recursive; see the dashboard-filters reference for the full grammar." + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] } }, "required": [ - "topicId" + "conjunction", + "filters", + "type" ] }, - "AiPickTopicBody": { - "allOf": [ - { - "$ref": "#/components/schemas/AiTopicParams" - }, - { - "type": "object", - "properties": { - "potentialTopicNames": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional list of topic names to limit consideration to. If not provided, all topics the user has access to in the model will be evaluated.", - "example": [ - "order_items", - "customers", - "products" - ] - }, - "prompt": { + "AiGenerateQueryResponse": { + "type": "object", + "properties": { + "baseView": { + "type": [ + "string", + "null" + ], + "description": "The base view name used for query generation when queryAllViews surfaced a non-topic view. Mutually exclusive with `topic` — exactly one is non-null when a query was generated.", + "example": null + }, + "downgradedModelTier": { + "type": "string", + "description": "Present only when the organization is over its AI downgrade threshold, signaling the query was generated on a downgraded (cheaper) model tier (e.g. 'haiku') to conserve credits. Advisory and best-effort — the call still succeeds, and clients may surface that a downgraded model was used. Absent when no downgrade applied.", + "example": "haiku" + }, + "error": { + "type": [ + "object", + "null" + ], + "properties": { + "detail": { "type": "string", - "description": "The natural language prompt to analyze. The AI will determine which topic best matches the data described in this prompt.", - "example": "How many orders were placed last month?" + "description": "Detailed error message explaining why query generation failed.", + "example": "The AI was unable to generate a query for this prompt. Try rephrasing your question to be more specific about the data you want to retrieve." }, - "userId": { + "message": { "type": "string", - "format": "uuid", - "description": "User ID to evaluate topic access as. Their permissions will be used for permission-aware topic selection. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", - "example": "990e8400-e29b-41d4-a716-446655440004" + "description": "Short error summary.", + "example": "No query generated" } }, "required": [ - "prompt" - ] + "detail", + "message" + ], + "description": "Error details if query generation failed. Null on success." + }, + "query": { + "$ref": "#/components/schemas/AiSemanticQuery" + }, + "result": { + "type": "object", + "additionalProperties": {}, + "description": "Query execution results as a JSON object. Only present when runQuery is true (the default) and the query executed successfully. The structure contains the query result data." + }, + "topic": { + "type": [ + "string", + "null" + ], + "description": "The topic name used for query generation. Mutually exclusive with `baseView` — exactly one is non-null when a query was generated.", + "example": "order_items" + }, + "workbookUrl": { + "type": "string", + "format": "uri", + "description": "URL to view and edit the generated query in an Omni workbook. Only present when workbookUrl was set to true in the request.", + "example": "https://myorg.omni.co/w/abc123/1" } + }, + "required": [ + "error", + "query" ] }, - "AiSearchOmniDocsResponse": { - "type": "object", + "AiSemanticQuery": { + "type": [ + "object", + "null" + ], "properties": { - "answer": { - "type": "string", - "description": "A synthesized answer to the question, based on the Omni documentation.", - "example": "To create a dashboard filter, navigate to your dashboard and click the \"Add Filter\" button..." + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of fully qualified field names to include in the query (e.g., \"view_name.field_name\").", + "example": [ + "products.name", + "order_items.total_revenue" + ] }, - "sources": { + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filter conditions keyed by fully qualified field name. Filter values vary by field type." + }, + "limit": { + "type": "integer", + "description": "Maximum number of rows to return.", + "example": 500 + }, + "sorts": { "type": "array", "items": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "The title of the source documentation page.", - "example": "Dashboard Filters" - }, - "url": { - "type": "string", - "format": "uri", - "description": "URL of the source documentation page.", - "example": "https://docs.omni.co/docs/dashboards/filters" - } - }, - "required": [ - "title", - "url" - ] + "$ref": "#/components/schemas/AiQuerySort" }, - "description": "List of documentation pages that were used to synthesize the answer." + "description": "Sort specifications applied to the query results." + }, + "table": { + "type": "string", + "description": "The base topic or view name for the query.", + "example": "order_items" } }, "required": [ - "answer", - "sources" - ] + "fields" + ], + "additionalProperties": {}, + "description": "The generated semantic query definition. Null if generation failed. This query can be passed directly to the POST /api/v1/query/run endpoint." }, - "AiSearchOmniDocsBody": { + "AiQuerySort": { "type": "object", "properties": { - "question": { + "column_name": { "type": "string", - "minLength": 1, - "maxLength": 2000, - "description": "A natural language question about Omni features, configuration, modeling, dashboards, or other topics covered in the Omni documentation.", - "example": "How do I create a dashboard filter?" + "description": "Fully qualified field name to sort by (e.g., \"view_name.field_name\").", + "example": "order_items.total_revenue" + }, + "sort_descending": { + "type": "boolean", + "description": "Whether to sort in descending order.", + "example": true } }, "required": [ - "question" + "column_name", + "sort_descending" ] }, - "AiJobSubmitResponse": { + "ApiError400": { "type": "object", "properties": { - "conversationId": { - "type": "string", - "format": "uuid", - "description": "The conversation ID for this job. Pass this as conversationId in subsequent job submissions to continue the conversation with additional context.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "jobId": { + "detail": { "type": "string", - "format": "uuid", - "description": "The unique identifier for the created job. Use this to poll status via GET /api/v1/ai/jobs/{jobId} or retrieve results via GET /api/v1/ai/jobs/{jobId}/result.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Human-readable error message describing what went wrong.", + "example": "Bad Request: prompt: Required" }, - "omniChatUrl": { - "type": "string", - "format": "uri", - "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", - "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 400 } }, "required": [ - "conversationId", - "jobId", - "omniChatUrl" + "detail", + "status" ] }, - "ApiError409": { + "ApiError401": { "type": "object", "properties": { "detail": { "type": "string", "description": "Human-readable error message describing what went wrong.", - "example": "An active job already exists for this conversation" + "example": "Unauthorized: Missing or invalid API key" }, "status": { "type": "integer", "description": "HTTP status code of the error.", - "example": 409 + "example": 401 } }, "required": [ @@ -526,845 +682,1021 @@ "status" ] }, - "AiJobSubmitBody": { + "AiCreditShutoffError": { "type": "object", "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Use this to query against in-progress model changes.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "conversationId": { - "type": "string", - "format": "uuid", - "description": "Conversation ID to continue an existing conversation thread. The AI will have access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. Only one active job can exist per conversation.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the shared model to query against. Only shared models are supported.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "progressWebhookEnabled": { - "type": "boolean", - "default": false, - "description": "When true, real-time progress events are POSTed to webhookUrl during execution (e.g., \"Searching for revenue fields\", \"Query returned 42 rows\"). Requires webhookUrl. Progress events are best-effort: single attempt, no retries, failures do not affect job execution.", - "example": true - }, - "prompt": { - "type": "string", - "minLength": 1, - "description": "The natural language prompt for the AI to process. The AI will analyze your question, generate appropriate queries, execute them, and return a summarized answer.", - "example": "What are the top 5 products by revenue this quarter?" - }, - "topicName": { + "code": { "type": "string", - "maxLength": 256, - "description": "Topic name to scope query generation. Topics define a set of related views and their join paths. If not provided, the AI will automatically select the best topic. Use the pick-topic endpoint to determine the right topic programmatically.", - "example": "order_items" - }, - "webhookMetadata": { - "type": "object", - "additionalProperties": {}, - "description": "Arbitrary metadata object that will be included unchanged in webhook payloads. Use this to correlate webhook notifications with your own system (e.g., tracking IDs, channel references).", - "example": { - "externalId": "task-123", - "slackChannel": "C0123456789" - } + "enum": [ + "shutoff" + ], + "description": "Stable reason code identifying an AI-credit shutoff.", + "example": "shutoff" }, - "webhookSigningSecret": { + "detail": { "type": "string", - "description": "Secret key for HMAC-SHA256 webhook payload signing. When provided, each webhook request includes X-Omni-Signature and X-Omni-Signature-Timestamp headers for verification. Required if webhookUrl is specified." + "description": "Human-readable error message describing what went wrong.", + "example": "The AI agent is currently unavailable. Contact your administrator to re-enable." }, - "webhookUrl": { - "type": "string", - "format": "uri", - "description": "URL to receive webhook POSTs. Always receives a terminal event (job.complete or job.failed) when the job finishes. When progressWebhookEnabled is true, also receives real-time progress events during execution.", - "example": "https://example.com/webhooks/omni" + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 402 } }, "required": [ - "modelId", - "prompt" + "code", + "detail", + "status" ] }, - "AiJobStatusResponse": { + "ApiError403": { "type": "object", "properties": { - "branchId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Branch ID used for model context, or null if querying the main shared model." - }, - "cancelledAt": { - "type": "string", - "format": "date-time", - "description": "When the job was cancelled. Only present in CANCELLED state.", - "example": "2025-01-15T10:00:12.000Z" - }, - "cancelledBy": { - "type": "string", - "format": "uuid", - "description": "User ID of who cancelled the job. Only present in CANCELLED state.", - "example": "990e8400-e29b-41d4-a716-446655440004" - }, - "completedAt": { + "detail": { "type": "string", - "format": "date-time", - "description": "When the job finished (successfully or with error). Present in COMPLETE and FAILED states.", - "example": "2025-01-15T10:01:30.000Z" + "description": "Human-readable error message describing what went wrong.", + "example": "Forbidden: AI query generation is not enabled for this organization" }, - "conversationId": { + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 403 + } + }, + "required": [ + "detail", + "status" + ] + }, + "ApiError404": { + "type": "object", + "properties": { + "detail": { "type": "string", - "format": "uuid", - "description": "The conversation this job belongs to. Use this to submit follow-up jobs in the same conversation thread.", - "example": "660e8400-e29b-41d4-a716-446655440001" + "description": "Human-readable error message describing what went wrong.", + "example": "Model 770e8400-e29b-41d4-a716-446655440002 not found" }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "When the job was submitted.", - "example": "2025-01-15T10:00:00.000Z" + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 404 + } + }, + "required": [ + "detail", + "status" + ] + }, + "AiGenerateQueryBody": { + "allOf": [ + { + "$ref": "#/components/schemas/AiTopicParams" }, - "error": { + { "type": "object", "properties": { - "code": { + "prompt": { "type": "string", - "description": "Machine-readable error code.", - "example": "QUERY_EXECUTION_ERROR" + "description": "The natural language prompt describing the data you want to retrieve.", + "example": "Show me total revenue by month for the last year" }, - "detail": { - "type": "string", - "description": "Additional error detail or context.", - "example": "The query timed out after 300 seconds" + "queryAllViews": { + "type": "boolean", + "description": "If true and the model has query_all_views_and_fields enabled, AI can query views not in any topic." }, - "message": { - "type": "string", - "description": "Human-readable error message.", - "example": "Column 'revenue' not found in table 'orders'" - } - }, - "required": [ - "message" - ], - "additionalProperties": {}, - "description": "Error details explaining why the job failed. Only present in FAILED state." - }, - "executionStartedAt": { - "type": "string", - "format": "date-time", - "description": "When execution began. Present once the job transitions from QUEUED to EXECUTING. May be absent on jobs that failed or were cancelled before execution started.", - "example": "2025-01-15T10:00:05.000Z" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "The unique identifier for this job.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "modelId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "The shared model ID used for query generation.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "omniChatUrl": { - "type": "string", - "format": "uri", - "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", - "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" - }, - "organizationId": { - "type": "string", - "format": "uuid", - "description": "The organization that owns this job.", - "example": "880e8400-e29b-41d4-a716-446655440003" - }, - "progress": { - "type": [ - "object", - "null" - ], - "properties": { - "iteration": { - "type": "integer", - "description": "Current iteration number. The AI may take multiple iterations to refine queries and generate a complete answer.", - "example": 2 + "runQuery": { + "type": "boolean", + "description": "Whether to execute the generated query and return results. Defaults to true. Set to false to only generate the query definition without executing it.", + "example": true }, - "message": { + "userId": { "type": "string", - "description": "Human-readable status message describing what the AI is currently doing.", - "example": "Running query: Top products by revenue" + "format": "uuid", + "description": "User ID to execute the query as. Their permissions will be applied for row-level security. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", + "example": "990e8400-e29b-41d4-a716-446655440004" }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "When this progress update was recorded.", - "example": "2025-01-15T10:00:08.000Z" + "workbookUrl": { + "type": "boolean", + "description": "If true, creates a new workbook with the generated query and returns its URL. Useful for sharing results or further exploration.", + "example": false } }, "required": [ - "iteration", - "message", - "updatedAt" - ], - "description": "Real-time progress information. Only present in EXECUTING state. Null if no progress has been reported yet. Updated in real-time as the AI works through iterations." - }, - "prompt": { - "type": "string", - "description": "The natural language prompt that was submitted.", - "example": "What are the top 5 products by revenue?" - }, - "resultSummary": { + "prompt" + ] + } + ] + }, + "AiTopicParams": { + "type": "object", + "properties": { + "branchId": { "type": "string", - "description": "Markdown-formatted summary of the job result. Only present in COMPLETE state. For the full result with query details and data, use GET /api/v1/ai/jobs/{jobId}/result.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "state": { + "currentTopicName": { "type": "string", - "enum": [ - "CANCELLED", - "COMPLETE", - "DELIVERING", - "EXECUTING", - "FAILED", - "QUEUED" - ], - "description": "Current state of the job. Terminal states are COMPLETE, FAILED, and CANCELLED. Poll until the job reaches a terminal state.", - "example": "QUEUED" - }, - "topicName": { - "type": [ - "string", - "null" - ], - "description": "Topic name used to scope query generation, or null if the AI selected the topic automatically.", + "description": "The name of the current topic to scope query generation. If not provided, AI will automatically select the best topic for your prompt.", "example": "order_items" }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "When the job record was last modified.", - "example": "2025-01-15T10:00:05.000Z" - }, - "userId": { + "modelId": { "type": "string", "format": "uuid", - "description": "The user ID who created (or is associated with) this job.", - "example": "990e8400-e29b-41d4-a716-446655440004" + "description": "The UUID of the shared model to query against. Only shared models are supported.", + "example": "770e8400-e29b-41d4-a716-446655440002" } }, "required": [ - "branchId", - "conversationId", - "createdAt", - "id", - "modelId", - "omniChatUrl", - "organizationId", - "prompt", - "state", - "topicName", - "updatedAt", - "userId" + "modelId" ] }, - "AiJobCancelResponse": { + "AiPickTopicResponse": { "type": "object", "properties": { - "jobId": { - "type": "string", - "format": "uuid", - "description": "The job ID that was requested to cancel.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "state": { + "topicId": { "type": "string", - "enum": [ - "CANCELLED", - "COMPLETE", - "DELIVERING", - "EXECUTING", - "FAILED", - "QUEUED" - ], - "description": "The job state after the cancellation attempt. CANCELLED if the cancellation was successful. If the job was already in a terminal state (COMPLETE, FAILED, CANCELLED), the current state is returned unchanged — the endpoint is idempotent.", - "example": "CANCELLED" + "description": "The name of the topic that best matches the prompt. Use this as the topicName parameter when calling generate-query or submitting an AI job.", + "example": "order_items" } }, "required": [ - "jobId", - "state" + "topicId" ] }, - "AiJobResultResponse": { - "type": "object", - "properties": { - "actions": { - "type": "array", + "AiPickTopicBody": { + "allOf": [ + { + "$ref": "#/components/schemas/AiTopicParams" + }, + { + "type": "object", + "properties": { + "potentialTopicNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional list of topic names to limit consideration to. If not provided, all topics the user has access to in the model will be evaluated.", + "example": [ + "order_items", + "customers", + "products" + ] + }, + "prompt": { + "type": "string", + "description": "The natural language prompt to analyze. The AI will determine which topic best matches the data described in this prompt.", + "example": "How many orders were placed last month?" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to evaluate topic access as. Their permissions will be used for permission-aware topic selection. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", + "example": "990e8400-e29b-41d4-a716-446655440004" + } + }, + "required": [ + "prompt" + ] + } + ] + }, + "AiSearchOmniDocsResponse": { + "type": "object", + "properties": { + "answer": { + "type": "string", + "description": "A synthesized answer to the question, based on the Omni documentation.", + "example": "To create a dashboard filter, navigate to your dashboard and click the \"Add Filter\" button..." + }, + "sources": { + "type": "array", "items": { - "$ref": "#/components/schemas/AiJobAction" + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the source documentation page.", + "example": "Dashboard Filters" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL of the source documentation page.", + "example": "https://docs.omni.co/docs/dashboards/filters" + } + }, + "required": [ + "title", + "url" + ] }, - "description": "Ordered list of actions the AI took during execution. Each action represents a step such as generating a query, executing it, or synthesizing a final answer." + "description": "List of documentation pages that were used to synthesize the answer." + } + }, + "required": [ + "answer", + "sources" + ] + }, + "AiSearchOmniDocsBody": { + "type": "object", + "properties": { + "question": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "description": "A natural language question about Omni features, configuration, modeling, dashboards, or other topics covered in the Omni documentation.", + "example": "How do I create a dashboard filter?" + } + }, + "required": [ + "question" + ] + }, + "AiJobSubmitResponse": { + "type": "object", + "properties": { + "conversationId": { + "type": "string", + "format": "uuid", + "description": "The conversation ID for this job. Pass this as conversationId in subsequent job submissions to continue the conversation with additional context.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "message": { + "jobId": { "type": "string", - "description": "The AI's final response message in Markdown format. This is the complete answer to the original prompt, incorporating data from all executed queries.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + "format": "uuid", + "description": "The unique identifier for the created job. Use this to poll status via GET /api/v1/ai/jobs/{jobId} or retrieve results via GET /api/v1/ai/jobs/{jobId}/result.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "omniChatUrl": { "type": "string", "format": "uri", "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" - }, - "resultSummary": { - "type": "string", - "description": "Summary of the job result. Typically matches the final message content.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" - }, - "topic": { - "type": "string", - "description": "The topic name used for query generation.", - "example": "order_items" } }, - "additionalProperties": {} + "required": [ + "conversationId", + "jobId", + "omniChatUrl" + ] }, - "AiJobAction": { + "ApiError409": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "The AI's explanation of what it is doing in this step, written in natural language.", - "example": "I'll generate a query to find the top 5 products by total revenue." - }, - "result": { - "$ref": "#/components/schemas/AiJobActionQueryResult" - }, - "timestamp": { + "detail": { "type": "string", - "description": "ISO 8601 timestamp when this action occurred.", - "example": "2025-01-15T10:00:10.000Z" + "description": "Human-readable error message describing what went wrong.", + "example": "An active job already exists for this conversation" }, - "type": { - "type": "string", - "description": "The type of action. Common types include \"generate_query\" (query generation and execution) and \"summarize\" (final answer synthesis).", - "example": "generate_query" + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 409 } }, "required": [ - "message", - "timestamp", - "type" - ], - "additionalProperties": {} + "detail", + "status" + ] }, - "AiJobActionQueryResult": { + "AiJobSubmitBody": { "type": "object", "properties": { - "csvResult": { + "branchId": { "type": "string", - "description": "Query results formatted as CSV text.", - "example": "Name,Total Revenue\nRay-Ban Sunglasses,\"678,994.41\"\nLevi's 501 Jeans,\"475,072.00\"" + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Use this to query against in-progress model changes.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "csvResultWasTruncated": { - "type": "boolean", - "description": "Whether the CSV data was truncated due to size limits. If true, the full result set may contain additional rows not included in csvResult.", - "example": false + "conversationId": { + "type": "string", + "format": "uuid", + "description": "Conversation ID to continue an existing conversation thread. The AI will have access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. Only one active job can exist per conversation.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "hasResults": { + "modelId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the shared model to query against. Only shared models are supported.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "progressWebhookEnabled": { "type": "boolean", - "description": "Whether the query returned any data rows.", + "default": false, + "description": "When true, real-time progress events are POSTed to webhookUrl during execution (e.g., \"Searching for revenue fields\", \"Query returned 42 rows\"). Requires webhookUrl. Progress events are best-effort: single attempt, no retries, failures do not affect job execution.", "example": true }, - "query": { - "type": "object", - "additionalProperties": {}, - "description": "The semantic query definition that was executed. This can be used with the POST /api/v1/query/run endpoint to re-run the query." + "prompt": { + "type": "string", + "minLength": 1, + "description": "The natural language prompt for the AI to process. The AI will analyze your question, generate appropriate queries, execute them, and return a summarized answer.", + "example": "What are the top 5 products by revenue this quarter?" }, - "queryName": { + "topicName": { "type": "string", - "description": "Human-readable name describing what this query retrieves.", - "example": "Top 5 Products by Revenue" + "maxLength": 256, + "description": "Topic name to scope query generation. Topics define a set of related views and their join paths. If not provided, the AI will automatically select the best topic. Use the pick-topic endpoint to determine the right topic programmatically.", + "example": "order_items" }, - "status": { + "webhookMetadata": { + "type": "object", + "additionalProperties": {}, + "description": "Arbitrary metadata object that will be included unchanged in webhook payloads. Use this to correlate webhook notifications with your own system (e.g., tracking IDs, channel references).", + "example": { + "externalId": "task-123", + "slackChannel": "C0123456789" + } + }, + "webhookSigningSecret": { "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Whether the query executed successfully.", - "example": "success" + "description": "Secret key for HMAC-SHA256 webhook payload signing. When provided, each webhook request includes X-Omni-Signature and X-Omni-Signature-Timestamp headers for verification. Required if webhookUrl is specified." }, - "totalRowCount": { - "type": "integer", - "description": "Total number of rows returned by the query.", - "example": 5 - } - }, - "required": [ - "csvResult", - "csvResultWasTruncated", - "hasResults", - "query", - "queryName", - "status", - "totalRowCount" - ], - "description": "Query result data. Only present for generate_query action types." - }, - "ApiError422": { - "type": "object", - "properties": { - "error": { + "webhookUrl": { "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "No Arrow IPC data available for visualization" + "format": "uri", + "description": "URL to receive webhook POSTs. Always receives a terminal event (job.complete or job.failed) when the job finishes. When progressWebhookEnabled is true, also receives real-time progress events during execution.", + "example": "https://example.com/webhooks/omni" } }, "required": [ - "error" + "modelId", + "prompt" ] }, - "ApiKeyListResponse": { + "AiJobStatusResponse": { "type": "object", "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApiKey" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "PageInfo": { - "type": "object", - "properties": { - "hasNextPage": { - "type": "boolean", - "description": "Whether more results are available" - }, - "nextCursor": { + "branchId": { "type": [ "string", "null" ], - "description": "Cursor for fetching the next page" + "format": "uuid", + "description": "Branch ID used for model context, or null if querying the main shared model." }, - "pageSize": { - "type": "number", - "description": "Number of results per page" + "cancelledAt": { + "type": "string", + "format": "date-time", + "description": "When the job was cancelled. Only present in CANCELLED state.", + "example": "2025-01-15T10:00:12.000Z" + }, + "cancelledBy": { + "type": "string", + "format": "uuid", + "description": "User ID of who cancelled the job. Only present in CANCELLED state.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "completedAt": { + "type": "string", + "format": "date-time", + "description": "When the job finished (successfully or with error). Present in COMPLETE and FAILED states.", + "example": "2025-01-15T10:01:30.000Z" + }, + "conversationId": { + "type": "string", + "format": "uuid", + "description": "The conversation this job belongs to. Use this to submit follow-up jobs in the same conversation thread.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "totalRecords": { - "type": "number", - "description": "Total number of records matching the query" - } - }, - "required": [ - "hasNextPage", - "nextCursor", - "pageSize", - "totalRecords" - ] - }, - "ApiKey": { - "type": "object", - "properties": { "createdAt": { "type": "string", "format": "date-time", - "description": "ISO 8601 timestamp of when the token was created", - "example": "2026-01-15T10:00:00.000Z" + "description": "When the job was submitted.", + "example": "2025-01-15T10:00:00.000Z" }, - "enabled": { - "type": "boolean", - "description": "Whether the token can currently authenticate. Organization tokens may be disabled by admins; personal and MCP tokens are always `true` (revocation deletes them).", - "example": true + "error": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable error code.", + "example": "QUERY_EXECUTION_ERROR" + }, + "detail": { + "type": "string", + "description": "Additional error detail or context.", + "example": "The query timed out after 300 seconds" + }, + "message": { + "type": "string", + "description": "Human-readable error message.", + "example": "Column 'revenue' not found in table 'orders'" + } + }, + "required": [ + "message" + ], + "additionalProperties": {}, + "description": "Error details explaining why the job failed. Only present in FAILED state." + }, + "executionStartedAt": { + "type": "string", + "format": "date-time", + "description": "When execution began. Present once the job transitions from QUEUED to EXECUTING. May be absent on jobs that failed or were cancelled before execution started.", + "example": "2025-01-15T10:00:05.000Z" }, "id": { "type": "string", "format": "uuid", - "description": "Unique identifier for the token", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "The unique identifier for this job.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "membershipId": { + "modelId": { "type": [ "string", "null" ], "format": "uuid", - "description": "Membership ID of the user the token is scoped to. Null for organization-level tokens.", - "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + "description": "The shared model ID used for query generation.", + "example": "770e8400-e29b-41d4-a716-446655440002" }, - "name": { + "omniChatUrl": { "type": "string", - "description": "Human-readable name for the token", - "example": "CI deployment key" + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" }, - "type": { + "organizationId": { + "type": "string", + "format": "uuid", + "description": "The organization that owns this job.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "progress": { + "type": [ + "object", + "null" + ], + "properties": { + "iteration": { + "type": "integer", + "description": "Current iteration number. The AI may take multiple iterations to refine queries and generate a complete answer.", + "example": 2 + }, + "message": { + "type": "string", + "description": "Human-readable status message describing what the AI is currently doing.", + "example": "Running query: Top products by revenue" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When this progress update was recorded.", + "example": "2025-01-15T10:00:08.000Z" + } + }, + "required": [ + "iteration", + "message", + "updatedAt" + ], + "description": "Real-time progress information. Only present in EXECUTING state. Null if no progress has been reported yet. Updated in real-time as the AI works through iterations." + }, + "prompt": { + "type": "string", + "description": "The natural language prompt that was submitted.", + "example": "What are the top 5 products by revenue?" + }, + "resultSummary": { + "type": "string", + "description": "Markdown-formatted summary of the job result. Only present in COMPLETE state. For the full result with query details and data, use GET /api/v1/ai/jobs/{jobId}/result.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "state": { "type": "string", "enum": [ - "organization", - "personal", - "mcp" + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" ], - "description": "Token type: `organization` (org-level), `personal` (user-created personal access token), or `mcp` (MCP OAuth grant).", - "example": "organization" + "description": "Current state of the job. Terminal states are COMPLETE, FAILED, and CANCELLED. Poll until the job reaches a terminal state.", + "example": "QUEUED" + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "Topic name used to scope query generation, or null if the AI selected the topic automatically.", + "example": "order_items" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the job record was last modified.", + "example": "2025-01-15T10:00:05.000Z" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "The user ID who created (or is associated with) this job.", + "example": "990e8400-e29b-41d4-a716-446655440004" } }, "required": [ + "branchId", + "conversationId", "createdAt", - "enabled", "id", - "membershipId", - "name", - "type" + "modelId", + "omniChatUrl", + "organizationId", + "prompt", + "state", + "topicName", + "updatedAt", + "userId" ] }, - "ApiKeyUpdateBody": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Set to `false` to disable the token, `true` to re-enable it. Only organization-level tokens may be disabled; personal and MCP tokens do not support this.", - "example": false - } - }, - "required": [ - "enabled" - ], - "additionalProperties": false - }, - "ApiKeyDeleteResponse": { + "AiJobCancelResponse": { "type": "object", "properties": { - "message": { + "jobId": { "type": "string", - "description": "Human-readable description of the outcome", - "example": "API token revoked" + "format": "uuid", + "description": "The job ID that was requested to cancel.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "success": { - "type": "boolean", + "state": { + "type": "string", "enum": [ - true + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" ], - "description": "Always `true` on a successful revocation" + "description": "The job state after the cancellation attempt. CANCELLED if the cancellation was successful. If the job was already in a terminal state (COMPLETE, FAILED, CANCELLED), the current state is returned unchanged — the endpoint is idempotent.", + "example": "CANCELLED" } }, "required": [ - "message", - "success" + "jobId", + "state" ] }, - "DbtEnvironmentListResponse": { + "AiJobResultResponse": { "type": "object", "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { + "actions": { "type": "array", "items": { - "$ref": "#/components/schemas/DbtEnvironmentItem" - } + "$ref": "#/components/schemas/AiJobAction" + }, + "description": "Ordered list of actions the AI took during execution. Each action represents a step such as generating a query, executing it, or synthesizing a final answer." + }, + "message": { + "type": "string", + "description": "The AI's final response message in Markdown format. This is the complete answer to the original prompt, incorporating data from all executed queries.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "omniChatUrl": { + "type": "string", + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + }, + "resultSummary": { + "type": "string", + "description": "Summary of the job result. Typically matches the final message content.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "topic": { + "type": "string", + "description": "The topic name used for query generation.", + "example": "order_items" + } + }, + "additionalProperties": {} + }, + "AiJobAction": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The AI's explanation of what it is doing in this step, written in natural language.", + "example": "I'll generate a query to find the top 5 products by total revenue." + }, + "result": { + "$ref": "#/components/schemas/AiJobActionQueryResult" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp when this action occurred.", + "example": "2025-01-15T10:00:10.000Z" + }, + "type": { + "type": "string", + "description": "The type of action. Common types include \"generate_query\" (query generation and execution) and \"summarize\" (final answer synthesis).", + "example": "generate_query" } }, "required": [ - "pageInfo", - "records" - ] + "message", + "timestamp", + "type" + ], + "additionalProperties": {} }, - "DbtEnvironmentItem": { + "AiJobActionQueryResult": { "type": "object", "properties": { - "id": { + "csvResult": { "type": "string", - "format": "uuid", - "description": "Unique environment identifier" + "description": "Query results formatted as CSV text.", + "example": "Name,Total Revenue\nRay-Ban Sunglasses,\"678,994.41\"\nLevi's 501 Jeans,\"475,072.00\"" }, - "isDefaultEnvironment": { + "csvResultWasTruncated": { "type": "boolean", - "description": "Whether this is the default environment" + "description": "Whether the CSV data was truncated due to size limits. If true, the full result set may contain additional rows not included in csvResult.", + "example": false }, - "name": { + "hasResults": { + "type": "boolean", + "description": "Whether the query returned any data rows.", + "example": true + }, + "query": { + "type": "object", + "additionalProperties": {}, + "description": "The semantic query definition that was executed. This can be used with the POST /api/v1/query/run endpoint to re-run the query." + }, + "queryName": { "type": "string", - "description": "Environment name" + "description": "Human-readable name describing what this query retrieves.", + "example": "Top 5 Products by Revenue" }, - "ownerId": { - "type": [ - "string", - "null" + "status": { + "type": "string", + "enum": [ + "success", + "error" ], - "description": "User ID of the environment owner, or null if not a personal environment" + "description": "Whether the query executed successfully.", + "example": "success" }, - "targetDatabase": { - "type": [ - "string", - "null" - ], - "description": "Target database override" + "totalRowCount": { + "type": "integer", + "description": "Total number of rows returned by the query.", + "example": 5 + } + }, + "required": [ + "csvResult", + "csvResultWasTruncated", + "hasResults", + "query", + "queryName", + "status", + "totalRowCount" + ], + "description": "Query result data. Only present for generate_query action types." + }, + "ApiError422": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "No Arrow IPC data available for visualization" + } + }, + "required": [ + "error" + ] + }, + "AiBrandingResponse": { + "type": "object", + "properties": { + "body": { + "type": "string", + "description": "Body / description copy shown beneath the headline on AI helper landing surfaces.", + "example": "Ask a data question to get started. I can help refine answers, adjust charts, or surface new areas to explore." }, - "targetName": { - "type": [ - "string", - "null" - ], - "description": "Target name override" + "headline": { + "type": "string", + "description": "Short headline shown on AI helper landing surfaces.", + "example": "What would you like to know?" }, - "targetRole": { + "logoUrl": { "type": [ "string", "null" ], - "description": "Target role override" + "format": "uri", + "description": "Absolute URL to a custom AI helper logo. `null` when the org has not configured a custom logo — clients should render their default avatar (e.g. Blobby).", + "example": "https://example.com/blobby.png" }, - "targetSchema": { + "name": { "type": "string", - "description": "Target schema" + "description": "Display name for the AI helper. Defaults to `Omni Agent` when no custom branding is set.", + "example": "Blobby" }, - "variables": { + "placeholder": { + "type": "string", + "description": "Placeholder text for the AI helper's prompt input.", + "example": "Ask a question about your data..." + } + }, + "required": [ + "body", + "headline", + "logoUrl", + "name", + "placeholder" + ] + }, + "AiConversationsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { "type": "array", "items": { - "$ref": "#/components/schemas/DbtEnvironmentResponseVariable" + "$ref": "#/components/schemas/AiConversation" }, - "description": "Environment variables" + "description": "Conversations ordered by updatedAt descending." } }, "required": [ - "id", - "isDefaultEnvironment", - "name", - "ownerId", - "targetDatabase", - "targetName", - "targetRole", - "targetSchema", - "variables" + "pageInfo", + "records" ] }, - "DbtEnvironmentResponseVariable": { + "PageInfo": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Variable ID" - }, - "isSecret": { + "hasNextPage": { "type": "boolean", - "description": "Whether the variable value is secret" - }, - "name": { - "type": "string", - "description": "Variable name" + "description": "Whether more results are available" }, - "value": { + "nextCursor": { "type": [ "string", "null" ], - "description": "Variable value (null for secret variables)" + "description": "Cursor for fetching the next page" + }, + "pageSize": { + "type": "number", + "description": "Number of results per page" + }, + "totalRecords": { + "type": "number", + "description": "Total number of records matching the query" } }, "required": [ - "id", - "isSecret", - "name", - "value" + "hasNextPage", + "nextCursor", + "pageSize", + "totalRecords" ] }, - "DbtEnvironmentCreateBody": { + "AiConversation": { "type": "object", "properties": { - "name": { + "createdAt": { "type": "string", - "minLength": 1, - "description": "Environment name", - "example": "PR_1111_Expose" - }, - "ownerId": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", - "example": null + "format": "date-time", + "description": "When the conversation was started.", + "example": "2025-01-15T10:00:00.000Z" }, - "targetDatabase": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "Target database override", - "example": "analytics_dev" + "id": { + "type": "string", + "format": "uuid", + "description": "Conversation ID. Pass as conversationId on subsequent /api/v1/ai/jobs submissions to continue this conversation.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "targetName": { + "lastPrompt": { "type": [ "string", "null" ], - "default": null, - "description": "Target name override", - "example": null + "description": "The most recent user prompt in this conversation, useful for displaying a one-line summary in a list.", + "example": "What were our top products last week?" }, - "targetRole": { + "name": { "type": [ "string", "null" ], - "default": null, - "description": "Target role override", - "example": null + "description": "Conversation title. Set by the AI after the first turn; null on brand-new sessions.", + "example": "Top products last week" }, - "targetSchema": { + "updatedAt": { "type": "string", - "minLength": 1, - "description": "Target schema for this environment", - "example": "PR_1111_Expose" - }, - "variables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtEnvironmentVariable" - }, - "default": [], - "description": "Environment variables" + "format": "date-time", + "description": "When the conversation was last touched (most recent prompt or AI activity).", + "example": "2025-01-15T10:01:30.000Z" } }, "required": [ + "createdAt", + "id", + "lastPrompt", "name", - "targetSchema" + "updatedAt" ] }, - "DbtEnvironmentVariable": { + "AiConversationDetailResponse": { "type": "object", "properties": { - "isSecret": { - "type": "boolean", - "description": "Whether the variable value is secret" + "createdAt": { + "type": "string", + "format": "date-time" }, - "name": { + "id": { "type": "string", - "minLength": 1, - "description": "Variable name" + "format": "uuid" }, - "value": { + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiConversationMessage" + }, + "description": "Messages in chronological order. Alternating user / assistant turns." + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "updatedAt": { "type": "string", - "description": "Variable value" + "format": "date-time" } }, "required": [ - "isSecret", + "createdAt", + "id", + "messages", "name", - "value" + "updatedAt" ] }, - "DbtEnvironmentUpdateBody": { + "AiConversationMessage": { "type": "object", "properties": { - "name": { + "createdAt": { "type": "string", - "minLength": 1, - "description": "Environment name", - "example": "PR_1111_Expose" + "format": "date-time", + "description": "When this turn was recorded.", + "example": "2025-01-15T10:00:00.000Z" }, - "ownerId": { + "jobId": { "type": [ "string", "null" ], - "default": null, - "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", - "example": null + "format": "uuid", + "description": "The agentic job that produced this assistant turn. Only set for assistant messages — clients use it to fetch the rendered chart via GET /api/v1/ai/jobs/{jobId}/vis. Null when the turn predates jobs or when we could not associate one.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "targetDatabase": { + "omniChatUrl": { "type": [ "string", "null" ], - "default": null, - "description": "Target database override", - "example": "analytics_dev" + "format": "uri", + "description": "Deep link to the assistant turn in the Omni chat UI. Null for user turns, and for assistant turns produced outside the Agentic API (where no AgenticJob row exists).", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" }, - "targetName": { - "type": [ - "string", - "null" + "role": { + "type": "string", + "enum": [ + "user", + "assistant" ], - "default": null, - "description": "Target name override", - "example": null + "description": "Speaker — `user` for prompts the user submitted, `assistant` for Blobby's responses.", + "example": "user" }, - "targetRole": { + "text": { + "type": "string", + "description": "Markdown content of the message. For assistant turns this is the same string returned by /api/v1/ai/jobs/{jobId}/result#message.", + "example": "What were our top products last week?" + } + }, + "required": [ + "createdAt", + "jobId", + "omniChatUrl", + "role", + "text" + ] + }, + "ApiKeyListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiKey" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "ApiKey": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of when the token was created", + "example": "2026-01-15T10:00:00.000Z" + }, + "enabled": { + "type": "boolean", + "description": "Whether the token can currently authenticate. A disabled token cannot authenticate but remains visible until deleted.", + "example": true + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the token", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "membershipId": { "type": [ "string", "null" ], - "default": null, - "description": "Target role override", - "example": null + "format": "uuid", + "description": "Membership ID of the user the token is scoped to. Null for organization-level tokens.", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" }, - "targetSchema": { + "name": { "type": "string", - "minLength": 1, - "description": "Target schema for this environment", - "example": "PR_1111_Expose" + "description": "Human-readable name for the token", + "example": "CI deployment key" }, - "variables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtEnvironmentVariableUpdateOrNew" - }, - "default": [], - "description": "Environment variables. Variables with an id update existing ones; variables without an id create new ones." + "type": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Token type: `organization` (org-level), `personal` (user-created personal access token), or `mcp` (MCP OAuth grant).", + "example": "organization" } }, "required": [ + "createdAt", + "enabled", + "id", + "membershipId", "name", - "targetSchema" + "type" ] }, - "DbtEnvironmentVariableUpdateOrNew": { - "oneOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentVariableUpdate" - }, - { - "$ref": "#/components/schemas/DbtEnvironmentVariable" + "ApiKeyUpdateBody": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Set to `false` to disable the token, `true` to re-enable it.", + "example": false } - ] + }, + "required": [ + "enabled" + ], + "additionalProperties": false }, - "DbtEnvironmentDeleteResponse": { + "ApiKeyDeleteResponse": { "type": "object", "properties": { "message": { "type": "string", - "description": "Confirmation message", - "example": "dbt environment deleted successfully" + "description": "Human-readable description of the outcome", + "example": "API token revoked" }, "success": { "type": "boolean", - "description": "Whether the deletion was successful", - "example": true + "enum": [ + true + ], + "description": "Always `true` on a successful revocation" } }, "required": [ @@ -1372,7 +1704,7 @@ "success" ] }, - "ContentListResponse": { + "DbtEnvironmentListResponse": { "type": "object", "properties": { "pageInfo": { @@ -1381,120 +1713,7 @@ "records": { "type": "array", "items": { - "oneOf": [ - { - "allOf": [ - { - "$ref": "#/components/schemas/ApiDocument" - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "document" - ] - } - }, - "required": [ - "type" - ] - } - ] - }, - { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Content name" - }, - "owner": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "User ID of the owner" - }, - "name": { - "type": "string", - "description": "Name of the owner" - } - }, - "required": [ - "id", - "name" - ], - "description": "Content owner" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Content access scope" - }, - "_count": { - "type": "object", - "properties": { - "documents": { - "type": "number", - "description": "Number of documents" - }, - "favorites": { - "type": "number", - "description": "Number of users who favorited" - } - }, - "required": [ - "documents", - "favorites" - ], - "description": "Folder counts" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels" - }, - "path": { - "type": "string", - "description": "Full path to the folder", - "example": "sales-reports/q1-2026" - }, - "url": { - "type": "string", - "description": "URL to view the folder in the Omni UI.", - "example": "https://org.omni.co/f/sales-reports" - }, - "type": { - "type": "string", - "enum": [ - "folder" - ] - } - }, - "required": [ - "id", - "name", - "owner", - "scope", - "path", - "url", - "type" - ] - } - ] + "$ref": "#/components/schemas/DbtEnvironmentItem" } } }, @@ -1503,406 +1722,428 @@ "records" ] }, - "OwnerInternal": { + "DbtEnvironmentItem": { "type": "object", "properties": { "id": { "type": "string", - "description": "Owner membership ID" - }, - "name": { - "type": "string", - "description": "Owner display name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Content owner" - }, - "ContentShareScope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Content access scope" - }, - "InternalFolder": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "description": "Folder ID" + "format": "uuid", + "description": "Unique environment identifier" }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Folder name" + "isDefaultEnvironment": { + "type": "boolean", + "description": "Whether this is the default environment" }, - "path": { - "type": "string", - "description": "Folder path" + "isDeferralEnabled": { + "type": "boolean", + "description": "Whether dbt deferral is enabled for this environment. Always false for the default (production) environment — the backend rejects enabling it there." }, - "scope": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentShareScope" - }, - { - "description": "Folder access scope" - } - ] - } - }, - "required": [ - "id", - "name", - "path", - "scope" - ], - "description": "Parent folder" - }, - "ApiDocument": { - "type": "object", - "properties": { "name": { "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Content name" - }, - "owner": { - "$ref": "#/components/schemas/OwnerInternal" - }, - "scope": { - "$ref": "#/components/schemas/ContentShareScope" + "description": "Environment name" }, - "_count": { - "type": "object", - "properties": { - "favorites": { - "type": "number", - "description": "Number of users who favorited" - }, - "views": { - "type": "number", - "description": "Number of views" - } - }, - "required": [ - "favorites", - "views" + "ownerId": { + "type": [ + "string", + "null" ], - "description": "Document counts" - }, - "connectionId": { - "type": "string", - "description": "Connection ID" - }, - "deleted": { - "type": "boolean", - "description": "Whether document is deleted" + "description": "User ID of the environment owner, or null if not a personal environment" }, - "description": { + "targetDatabase": { "type": [ "string", "null" ], - "description": "Document description" - }, - "folder": { - "$ref": "#/components/schemas/InternalFolder" - }, - "hasDashboard": { - "type": "boolean", - "description": "Whether document has a dashboard" - }, - "identifier": { - "type": "string", - "description": "Document identifier" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Applied labels" + "description": "Target database override" }, - "lastViewedAt": { + "targetName": { "type": [ "string", "null" ], - "format": "date-time", - "description": "Last time the dashboard was viewed" + "description": "Target name override" }, - "updatedAt": { + "targetRole": { "type": [ "string", "null" ], - "format": "date-time", - "description": "Last updated timestamp" + "description": "Target role override" }, - "url": { + "targetSchema": { "type": "string", - "description": "URL to view the document. Returns dashboard URL if document has a dashboard, otherwise workbook URL.", - "example": "https://org.omni.co/dashboards/abc123" + "description": "Target schema" }, - "visits": { - "type": [ - "number", - "null" - ], - "description": "Number of dashboard visits" + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentResponseVariable" + }, + "description": "Environment variables" } }, "required": [ + "id", + "isDefaultEnvironment", + "isDeferralEnabled", "name", - "owner", - "scope", - "connectionId", - "deleted", - "folder", - "hasDashboard", - "identifier", - "updatedAt", - "url" + "ownerId", + "targetDatabase", + "targetName", + "targetRole", + "targetSchema", + "variables" ] }, - "DashboardsDownloadResponse": { + "DbtEnvironmentResponseVariable": { "type": "object", "properties": { - "job_id": { + "id": { "type": "string", "format": "uuid", - "description": "ID of the download job. Use this to poll for download status.", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Variable ID" }, - "message": { + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" + }, + "name": { "type": "string", - "description": "Status message", - "example": "Download initiated successfully" + "description": "Variable name" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "Variable value (null for secret variables)" } }, "required": [ - "job_id", - "message" + "id", + "isSecret", + "name", + "value" ] }, - "DashboardsDownloadBody": { + "DbtEnvironmentCreateBody": { "type": "object", "properties": { - "enableFormatting": { + "isDeferralEnabled": { "type": "boolean", "default": false, - "description": "Compatible with csv, xlsx & json formats. If true, formatting will be enabled in the output. Note: If true for json format, a queryIdentifierMapKey is required.", + "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", "example": false }, - "expandTablesToShowAllRows": { - "type": "boolean", - "description": "Compatible with pdf and png formats. If true, up to 1,000 rows in table visualizations will be included in the delivery. Note: This parameter cannot be used when paperFormat: fit_page.", - "example": false - }, - "filterConfig": { - "description": "An object specifying the filter conditions to apply to the task. The filter key specified must already exist in the dashboard.", - "example": { - "status": [ - "active", - "pending" - ] - } - }, - "format": { + "name": { "type": "string", - "enum": [ - "pdf", - "png", - "csv", - "xlsx", - "json" - ], - "description": "Output format for the download: pdf, png, csv, xlsx, or json", - "example": "pdf" - }, - "hideHiddenFields": { - "type": "boolean", - "default": false, - "description": "Compatible with csv & xlsx formats. If true, fields marked as hidden won't be displayed in the output.", - "example": false - }, - "hideTitle": { - "type": "boolean", - "default": false, - "description": "Compatible with pdf & png formats. If true, the content's title will be hidden in the output.", - "example": false - }, - "maxRowLimit": { - "type": "number", - "minimum": 1, - "description": "Compatible with csv, json, & xlsx formats. Used with overrideRowLimit. Specifies the maximum number of rows.", - "example": 1000 - }, - "overrideRowLimit": { - "type": "boolean", - "default": false, - "description": "Compatible with csv, json, & xlsx formats. If true, the default row limit will be overridden. Note: If true for json and xlsx formats, a queryIdentifierMapKey is required.", - "example": false + "minLength": 1, + "description": "Environment name", + "example": "PR_1111_Expose" }, - "paperFormat": { - "type": "string", - "enum": [ - "a3", - "a4", - "fit_page", - "legal", - "letter", - "tabloid" + "ownerId": { + "type": [ + "string", + "null" ], - "description": "Compatible with pdf formats. Defines the paper format (size) of the resulting PDF. Must be one of: a3, a4, letter, legal, fit_page, tabloid.", - "example": "letter" + "default": null, + "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", + "example": null }, - "paperOrientation": { - "type": "string", - "enum": [ - "portrait", - "landscape" + "targetDatabase": { + "type": [ + "string", + "null" ], - "description": "Compatible with pdf formats. Defines the paper orientation of the resulting PDF. Must be one of: portrait, landscape.", - "example": "landscape" - }, - "queryIdentifierMapKey": { - "type": "string", - "description": "Required for single tile tasks. The ID of the query to include in a single tile task. Must reference a valid query in the dashboard.", - "example": "Jmn2r3KV" - }, - "showContentLink": { - "type": "boolean", - "default": true, - "description": "Compatible with all formats except link_only. If true, a link to the content will be shown in the output.", - "example": true - }, - "showFilters": { - "type": "boolean", - "default": true, - "description": "Compatible with all formats except link_only & csv. If true, filters will be shown in the output.", - "example": true + "default": null, + "description": "Target database override", + "example": "analytics_dev" }, - "singleColumnLayout": { - "type": "boolean", - "description": "Compatible with pdf and png formats. If true, dashboard tiles will be arranged into a single vertical column.", - "example": false + "targetName": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target name override", + "example": null }, - "useCache": { - "type": "boolean", - "default": false, - "description": "If true, allow scheduled queries to use cached results instead of always running fresh queries.", - "example": false + "targetRole": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target role override", + "example": null }, - "filename": { + "targetSchema": { "type": "string", "minLength": 1, - "maxLength": 255, - "description": "Custom filename for the downloaded file (without extension)", - "example": "monthly-report" + "description": "Target schema for this environment", + "example": "PR_1111_Expose" + }, + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentVariable" + }, + "default": [], + "description": "Environment variables" } }, "required": [ - "format" - ], - "additionalProperties": false + "name", + "targetSchema" + ] }, - "DashboardFiltersResponse": { + "DbtEnvironmentVariable": { "type": "object", "properties": { - "controls": { - "description": "Control configuration object. Keys are control IDs, values contain controlType, filterId, label, etc." - }, - "filterOrder": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Ordered list of filter IDs defining display order", - "example": [ - "filter_abc123", - "filter_def456" - ] + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" }, - "filters": { - "description": "Filter configuration object. Keys are filter IDs, values contain fieldName, viewName, kind, defaultValue, etc." + "name": { + "type": "string", + "minLength": 1, + "description": "Variable name" }, - "identifier": { + "value": { "type": "string", - "description": "Dashboard identifier", - "example": "12db1a0a" + "description": "Variable value" } }, "required": [ - "filterOrder", - "identifier" + "isSecret", + "name", + "value" ] }, - "DashboardsUpdateFiltersBody": { + "DbtEnvironmentUpdateBody": { "type": "object", "properties": { - "clearExistingDraft": { + "isDeferralEnabled": { "type": "boolean", "default": false, - "description": "When true, discards any existing draft before applying updates. Required when updating a published document that already has a draft." + "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", + "example": false }, - "controls": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": {}, - "additionalProperties": {} - }, - "description": "Partial control updates. Keys are control IDs that must exist in the dashboard." + "name": { + "type": "string", + "minLength": 1, + "description": "Environment name", + "example": "PR_1111_Expose" }, - "filterOrder": { + "ownerId": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", + "example": null + }, + "targetDatabase": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target database override", + "example": "analytics_dev" + }, + "targetName": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target name override", + "example": null + }, + "targetRole": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target role override", + "example": null + }, + "targetSchema": { + "type": "string", + "minLength": 1, + "description": "Target schema for this environment", + "example": "PR_1111_Expose" + }, + "variables": { "type": "array", "items": { - "type": "string" - }, - "description": "New order for filters. All filter IDs must exist in the dashboard." - }, - "filters": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": {}, - "additionalProperties": {} + "$ref": "#/components/schemas/DbtEnvironmentVariableUpdateOrNew" }, - "description": "Partial filter updates. Keys are filter IDs that must exist in the dashboard." + "default": [], + "description": "Environment variables. Variables with an id update existing ones; variables without an id create new ones." } - } + }, + "required": [ + "name", + "targetSchema" + ] }, - "DocumentsListResponse": { + "DbtEnvironmentVariableUpdateOrNew": { + "oneOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentVariableUpdate" + }, + { + "$ref": "#/components/schemas/DbtEnvironmentVariable" + } + ] + }, + "DbtEnvironmentDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Confirmation message", + "example": "dbt environment deleted successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the deletion was successful", + "example": true + } + }, + "required": [ + "message", + "success" + ] + }, + "ContentListResponse": { "type": "object", "properties": { "pageInfo": { - "allOf": [ - { - "$ref": "#/components/schemas/PageInfo" - }, - { - "description": "Pagination information" - } - ] + "$ref": "#/components/schemas/PageInfo" }, "records": { "type": "array", "items": { - "$ref": "#/components/schemas/Document" - }, - "description": "List of documents" + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/ApiDocument" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "document" + ] + } + }, + "required": [ + "type" + ] + } + ] + }, + { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Content name" + }, + "owner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "User ID of the owner" + }, + "name": { + "type": "string", + "description": "Name of the owner" + } + }, + "required": [ + "id", + "name" + ], + "description": "Content owner" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Content access scope" + }, + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents" + }, + "favorites": { + "type": "number", + "description": "Number of users who favorited" + } + }, + "required": [ + "documents", + "favorites" + ], + "description": "Folder counts" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels" + }, + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "sales-reports/q1-2026" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/sales-reports" + }, + "type": { + "type": "string", + "enum": [ + "folder" + ] + } + }, + "required": [ + "id", + "name", + "owner", + "scope", + "path", + "url", + "type" + ] + } + ] + } } }, "required": [ @@ -1910,15 +2151,92 @@ "records" ] }, - "Document": { + "OwnerInternal": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Owner membership ID" + }, + "name": { + "type": "string", + "description": "Owner display name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Content owner" + }, + "ContentShareScope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Content access scope" + }, + "InternalFolder": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Folder ID" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Folder name" + }, + "path": { + "type": "string", + "description": "Folder path" + }, + "scope": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentShareScope" + }, + { + "description": "Folder access scope" + } + ] + } + }, + "required": [ + "id", + "name", + "path", + "scope" + ], + "description": "Parent folder" + }, + "ApiDocument": { "type": "object", "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Content name" + }, + "owner": { + "$ref": "#/components/schemas/OwnerInternal" + }, + "scope": { + "$ref": "#/components/schemas/ContentShareScope" + }, "_count": { "type": "object", "properties": { "favorites": { "type": "number", - "description": "Number of users who favorited this document" + "description": "Number of users who favorited" }, "views": { "type": "number", @@ -1929,15 +2247,15 @@ "favorites", "views" ], - "description": "Document counts (included when _count is in include param)" + "description": "Document counts" }, "connectionId": { "type": "string", - "description": "Connection ID the document is associated with" + "description": "Connection ID" }, "deleted": { "type": "boolean", - "description": "Whether the document is deleted (archived)" + "description": "Whether document is deleted" }, "description": { "type": [ @@ -1947,45 +2265,34 @@ "description": "Document description" }, "folder": { - "$ref": "#/components/schemas/DocumentFolder" + "$ref": "#/components/schemas/InternalFolder" + }, + "hasApp": { + "type": "boolean", + "description": "Whether document has an app" }, "hasDashboard": { "type": "boolean", - "description": "Whether the document has an associated dashboard" + "description": "Whether document has a dashboard" }, "identifier": { "type": "string", - "description": "Document identifier", - "example": "abc123" + "description": "Document identifier" }, "labels": { "type": "array", "items": { "type": "string" }, - "description": "Labels applied to the document (included when labels is in include param)" - }, - "name": { - "type": "string", - "description": "Document name" - }, - "owner": { - "$ref": "#/components/schemas/DocumentOwner" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Document access scope" + "description": "Applied labels" }, - "type": { - "type": "string", - "enum": [ - "document" + "lastViewedAt": { + "type": [ + "string", + "null" ], - "description": "Content type" + "format": "date-time", + "description": "Last time the dashboard was viewed" }, "updatedAt": { "type": [ @@ -1997,101 +2304,451 @@ }, "url": { "type": "string", - "description": "URL to view the document. Returns dashboard URL if document has a dashboard, otherwise workbook URL.", + "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", "example": "https://org.omni.co/dashboards/abc123" + }, + "visits": { + "type": [ + "number", + "null" + ], + "description": "Number of dashboard visits" } }, "required": [ + "name", + "owner", + "scope", "connectionId", "deleted", "folder", + "hasApp", "hasDashboard", "identifier", - "name", - "owner", - "scope", - "type", "updatedAt", "url" ] }, - "DocumentFolder": { - "type": [ - "object", - "null" - ], + "DashboardsDownloadResponse": { + "type": "object", "properties": { - "id": { + "job_id": { "type": "string", - "description": "Folder ID" + "format": "uuid", + "description": "ID of the download job. Use this to poll for download status.", + "example": "123e4567-e89b-12d3-a456-426614174000" }, - "name": { + "message": { "type": "string", - "description": "Folder name" + "description": "Status message", + "example": "Download initiated successfully" + } + }, + "required": [ + "job_id", + "message" + ] + }, + "DashboardsDownloadBody": { + "type": "object", + "properties": { + "enableFormatting": { + "type": "boolean", + "default": false, + "description": "Compatible with csv, xlsx & json formats. If true, formatting will be enabled in the output. Note: If true for json format, a queryIdentifierMapKey is required.", + "example": false }, - "path": { + "expandTablesToShowAllRows": { + "type": "boolean", + "description": "Compatible with pdf and png formats. If true, up to 1,000 rows in table visualizations will be included in the delivery. Note: This parameter cannot be used when paperFormat: fit_page.", + "example": false + }, + "filterConfig": { + "description": "An object specifying the filter conditions to apply to the task. The filter key specified must already exist in the dashboard.", + "example": { + "status": [ + "active", + "pending" + ] + } + }, + "format": { "type": "string", - "description": "Folder path" + "enum": [ + "pdf", + "png", + "csv", + "xlsx", + "json" + ], + "description": "Output format for the download: pdf, png, csv, xlsx, or json", + "example": "pdf" }, - "scope": { + "hideHiddenFields": { + "type": "boolean", + "default": false, + "description": "Compatible with csv & xlsx formats. If true, fields marked as hidden won't be displayed in the output.", + "example": false + }, + "hideTitle": { + "type": "boolean", + "default": false, + "description": "Compatible with pdf & png formats. If true, the content's title will be hidden in the output.", + "example": false + }, + "maxRowLimit": { + "type": "number", + "minimum": 1, + "description": "Compatible with csv, json, & xlsx formats. Used with overrideRowLimit. Specifies the maximum number of rows.", + "example": 1000 + }, + "overrideRowLimit": { + "type": "boolean", + "default": false, + "description": "Compatible with csv, json, & xlsx formats. If true, the default row limit will be overridden. Note: If true for json and xlsx formats, a queryIdentifierMapKey is required.", + "example": false + }, + "paperFormat": { "type": "string", "enum": [ - "restricted", - "organization" + "a3", + "a4", + "fit_page", + "legal", + "letter", + "tabloid" ], - "description": "Folder access scope" + "description": "Compatible with pdf formats. Defines the paper format (size) of the resulting PDF. Must be one of: a3, a4, letter, legal, fit_page, tabloid.", + "example": "letter" + }, + "paperOrientation": { + "type": "string", + "enum": [ + "portrait", + "landscape" + ], + "description": "Compatible with pdf formats. Defines the paper orientation of the resulting PDF. Must be one of: portrait, landscape.", + "example": "landscape" + }, + "queryIdentifierMapKey": { + "type": "string", + "description": "Required for single tile tasks. The ID of the query to include in a single tile task. Must reference a valid query in the dashboard.", + "example": "Jmn2r3KV" + }, + "showContentLink": { + "type": "boolean", + "default": true, + "description": "Compatible with all formats except link_only. If true, a link to the content will be shown in the output.", + "example": true + }, + "showFilters": { + "type": "boolean", + "default": true, + "description": "Compatible with all formats except link_only & csv. If true, filters will be shown in the output.", + "example": true + }, + "singleColumnLayout": { + "type": "boolean", + "description": "Compatible with pdf and png formats. If true, dashboard tiles will be arranged into a single vertical column.", + "example": false + }, + "useCache": { + "type": "boolean", + "default": false, + "description": "If true, allow scheduled queries to use cached results instead of always running fresh queries.", + "example": false + }, + "filename": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Custom filename for the downloaded file (without extension)", + "example": "monthly-report" } }, "required": [ - "id", - "name", - "path", - "scope" + "format" ], - "description": "Folder containing the document" + "additionalProperties": false }, - "DocumentOwner": { + "DashboardFiltersResponse": { "type": "object", "properties": { - "id": { - "type": "string", - "description": "Owner membership ID" + "controls": { + "description": "Control configuration object. Keys are control IDs, values contain controlType, filterId, label, etc." }, - "name": { + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter IDs defining display order", + "example": [ + "filter_abc123", + "filter_def456" + ] + }, + "filters": { + "description": "Filter configuration object. Keys are filter IDs, values contain fieldName, viewName, kind, defaultValue, etc." + }, + "identifier": { "type": "string", - "description": "Owner display name" + "description": "Dashboard identifier", + "example": "12db1a0a" } }, "required": [ - "id", - "name" - ], - "description": "Document owner" + "filterOrder", + "identifier" + ] }, - "DocumentsCreateResponse": { + "DashboardsUpdateFiltersBody": { "type": "object", "properties": { - "dashboard": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "When true, discards any existing draft before applying updates. Required when updating a published document that already has a draft." + }, + "controls": { "type": "object", - "properties": { - "dashboardId": { - "type": "string", - "description": "Dashboard ID" - }, - "id": { - "type": "string", - "description": "Dashboard ID" - } + "additionalProperties": { + "type": "object", + "properties": {}, + "additionalProperties": {} }, - "required": [ - "dashboardId", - "id" - ], - "additionalProperties": {}, - "description": "Created dashboard" + "description": "Partial control updates. Keys are control IDs that must exist in the dashboard." }, - "workbook": { - "type": "object", + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "New order for filters. All filter IDs must exist in the dashboard." + }, + "filters": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": {}, + "additionalProperties": {} + }, + "description": "Partial filter updates. Keys are filter IDs that must exist in the dashboard." + } + } + }, + "DocumentsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Document" + }, + "description": "List of documents" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Document": { + "type": "object", + "properties": { + "_count": { + "type": "object", + "properties": { + "favorites": { + "type": "number", + "description": "Number of users who favorited this document" + }, + "views": { + "type": "number", + "description": "Number of views" + } + }, + "required": [ + "favorites", + "views" + ], + "description": "Document counts (included when _count is in include param)" + }, + "connectionId": { + "type": "string", + "description": "Connection ID the document is associated with" + }, + "deleted": { + "type": "boolean", + "description": "Whether the document is deleted (archived)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "folder": { + "$ref": "#/components/schemas/DocumentFolder" + }, + "hasApp": { + "type": "boolean", + "description": "Whether the document has an associated app" + }, + "hasDashboard": { + "type": "boolean", + "description": "Whether the document has an associated dashboard" + }, + "identifier": { + "type": "string", + "description": "Document identifier", + "example": "abc123" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels applied to the document (included when labels is in include param)" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "owner": { + "$ref": "#/components/schemas/DocumentOwner" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Document access scope" + }, + "type": { + "type": "string", + "enum": [ + "document" + ], + "description": "Content type" + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Last updated timestamp" + }, + "url": { + "type": "string", + "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", + "example": "https://org.omni.co/dashboards/abc123" + } + }, + "required": [ + "connectionId", + "deleted", + "folder", + "hasDashboard", + "identifier", + "name", + "owner", + "scope", + "type", + "updatedAt", + "url" + ] + }, + "DocumentFolder": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Folder ID" + }, + "name": { + "type": "string", + "description": "Folder name" + }, + "path": { + "type": "string", + "description": "Folder path" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Folder access scope" + } + }, + "required": [ + "id", + "name", + "path", + "scope" + ], + "description": "Folder containing the document" + }, + "DocumentOwner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Owner membership ID" + }, + "name": { + "type": "string", + "description": "Owner display name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Document owner" + }, + "DocumentsCreateResponse": { + "type": "object", + "properties": { + "dashboard": { + "type": "object", + "properties": { + "dashboardId": { + "type": "string", + "description": "Dashboard ID" + }, + "id": { + "type": "string", + "description": "Dashboard ID" + } + }, + "required": [ + "dashboardId", + "id" + ], + "additionalProperties": {}, + "description": "Created dashboard" + }, + "workbook": { + "type": "object", "properties": { "documentId": { "type": "string", @@ -2180,10 +2837,13 @@ }, "description": { "type": "string", + "maxLength": 500, "description": "Query presentation description" }, "name": { "type": "string", + "minLength": 1, + "maxLength": 144, "description": "Query presentation name" }, "prefersChart": { @@ -2217,11 +2877,16 @@ }, "subTitle": { "type": "string", + "maxLength": 250, "description": "Subtitle" }, "topicName": { - "type": "string", - "description": "Topic name" + "type": [ + "string", + "null" + ], + "maxLength": 256, + "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." }, "visConfig": { "$ref": "#/components/schemas/ApiVisConfig" @@ -2247,7 +2912,10 @@ "description": "Optional document identifier. If omitted, an identifier is auto-generated. Must be unique within the organization." }, "ApiVisConfig": { - "type": "object", + "type": [ + "object", + "null" + ], "properties": { "config": { "type": "object", @@ -2517,10 +3185,13 @@ }, "description": { "type": "string", + "maxLength": 500, "description": "Description" }, "name": { "type": "string", + "minLength": 1, + "maxLength": 144, "description": "Query presentation name" }, "prefersChart": { @@ -2530,16 +3201,26 @@ "query": { "description": "Query definition" }, + "queryIdentifierMapKey": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "Round-trip preservation hint. When the value matches an existing key on the document, the tile keeps its map key (and dashboard containers stay attached). Omit for new tiles. Must be a positive integer string (e.g. \"1\", \"2\", \"10\")." + }, "resultConfig": { "description": "Result config" }, "subTitle": { "type": "string", + "maxLength": 250, "description": "Subtitle" }, "topicName": { - "type": "string", - "description": "Topic name" + "type": [ + "string", + "null" + ], + "maxLength": 256, + "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." }, "visConfig": { "$ref": "#/components/schemas/ApiVisConfig" @@ -2720,6 +3401,10 @@ "type": "boolean", "description": "Allow using dashboard AI" }, + "canUseTimezoneOverride": { + "type": "boolean", + "description": "Allow timezone override" + }, "canViewWorkbook": { "type": "boolean", "description": "Allow viewing workbook" @@ -2888,10 +3573,122 @@ } } }, - "DocumentsDuplicateResponse": { + "DocumentsListDraftsResponse": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiDraft" + } + }, + "ApiDraft": { "type": "object", "properties": { - "dashboardId": { + "branch": { + "$ref": "#/components/schemas/ApiDraftBranch" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the draft was created" + }, + "createdBy": { + "$ref": "#/components/schemas/ApiDraftActor" + }, + "draftOutOfDate": { + "type": "boolean", + "description": "True when the published document was published more recently than the draft was created (the draft is based on a stale baseline)" + }, + "identifier": { + "type": "string", + "description": "Draft workbook identifier — use this to address the draft" + }, + "lastEditedBy": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiDraftActor" + }, + { + "description": "User who most recently edited the draft" + } + ] + }, + "publishedIdentifier": { + "type": "string", + "description": "Identifier of the published document the draft is for" + }, + "status": { + "$ref": "#/components/schemas/ApiDraftStatus" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Most recent edit time on the draft workbook" + }, + "workbookModelId": { + "type": "string", + "format": "uuid", + "description": "omni_model ID for the draft workbook" + } + }, + "required": [ + "branch", + "createdAt", + "createdBy", + "draftOutOfDate", + "identifier", + "lastEditedBy", + "publishedIdentifier", + "status", + "updatedAt", + "workbookModelId" + ] + }, + "ApiDraftBranch": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Branch (omni model) ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Branch the draft is attached to, or null for a draft on main" + }, + "ApiDraftActor": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Display name" + } + }, + "required": [ + "name" + ], + "description": "User who created the draft" + }, + "ApiDraftStatus": { + "type": "string", + "enum": [ + "active", + "archived" + ], + "description": "Lifecycle status: \"active\" for current drafts, \"archived\" for soft-deleted drafts (retained ~7 days)" + }, + "DocumentsDuplicateResponse": { + "type": "object", + "properties": { + "dashboardId": { "type": "string", "description": "New dashboard ID" }, @@ -3017,54 +3814,7 @@ "principals" ] }, - "EmbedSsoGenerateSessionResponse": { - "type": "object", - "properties": { - "sessionId": { - "type": "string", - "description": "Session ID to use for embedding Omni content" - } - }, - "required": [ - "sessionId" - ] - }, - "EmbedSsoGenerateSessionBody": { - "type": "object", - "properties": { - "externalId": { - "type": "string", - "description": "External identifier for the user (from your system)", - "example": "user-123" - }, - "groups": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional list of group names to assign to the user", - "example": [ - "engineering", - "sales" - ] - }, - "name": { - "type": "string", - "description": "Display name for the user", - "example": "John Doe" - }, - "userAttributes": { - "type": "object", - "additionalProperties": {}, - "description": "Optional user attributes for row-level security" - } - }, - "required": [ - "externalId", - "name" - ] - }, - "FoldersListResponse": { + "DocumentsListFavoritesResponse": { "type": "object", "properties": { "pageInfo": { @@ -3080,68 +3830,9 @@ "records": { "type": "array", "items": { - "type": "object", - "properties": { - "_count": { - "type": "object", - "properties": { - "documents": { - "type": "number", - "description": "Number of documents in the folder" - }, - "favorites": { - "type": "number", - "description": "Number of users who have favorited this folder" - } - }, - "required": [ - "documents", - "favorites" - ], - "description": "Count statistics for the folder" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique folder identifier" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels associated with the folder" - }, - "name": { - "type": "string", - "description": "Name of the folder", - "example": "My Reports" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the folder owner" - }, - "path": { - "type": "string", - "description": "Full path to the folder", - "example": "/shared/reports/my-reports" - }, - "url": { - "type": "string", - "description": "URL to view the folder in the Omni UI.", - "example": "https://org.omni.co/f/my-reports" - } - }, - "required": [ - "id", - "name", - "ownerId", - "path", - "url" - ] + "$ref": "#/components/schemas/DocumentFavoriteUser" }, - "description": "List of folders" + "description": "Users who favorited this document" } }, "required": [ @@ -3149,1744 +3840,22830 @@ "records" ] }, - "FoldersCreateResponse": { + "DocumentFavoriteUser": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "ID of the created folder" - }, - "name": { - "type": "string", - "description": "Name of the created folder" + "email": { + "type": [ + "string", + "null" + ], + "description": "Favoriting user's email. Null when the user has no resolvable email — e.g. an embed-SSO favoriter whose embed session did not provide one." }, - "ownerId": { + "favoritedAt": { "type": "string", - "format": "uuid", - "description": "User ID of the folder owner" + "description": "ISO 8601 timestamp when the user favorited the document" }, - "path": { + "name": { "type": "string", - "description": "Full path to the folder" + "description": "Favoriting user's display name" }, - "scope": { + "userId": { "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Share scope of the folder" + "description": "Membership ID of the user who favorited the document (use with other v1 endpoints' userId parameter)" } }, "required": [ - "id", + "email", + "favoritedAt", "name", - "ownerId", - "path", - "scope" + "userId" ] }, - "FoldersCreateBody": { + "DocumentsV2CreateResponse": { "type": "object", "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "Name of the folder to create", - "example": "My New Folder" - }, - "parentFolderId": { - "type": "string", - "format": "uuid", - "description": "Parent folder ID (omit to create at root level)" + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." }, - "scope": { + "identifier": { "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Share scope for the folder" + "description": "Identifier of the newly created document." }, - "userId": { + "name": { "type": "string", - "format": "uuid", - "description": "User ID to create the folder as (for org-scoped API keys only)" + "description": "Document name." } }, "required": [ + "description", + "identifier", "name" ] }, - "FoldersDeleteResponse": { + "DocumentsV2CreateBody": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the folder was deleted successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersUpdateResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", + "containers": { + "$ref": "#/components/schemas/Containers" + }, + "controls": { + "$ref": "#/components/schemas/ControlsPatchExternal" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "folderId": { + "type": [ + "string", + "null" + ], "format": "uuid", - "description": "Folder ID" + "description": "Folder to create the document in. When omitted, defaults to the caller’s personal \"My documents\" (requires permission to save personal content — otherwise the request is rejected)." }, - "name": { - "type": "string", - "description": "Updated folder name" + "identifier": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + { + "description": "Identifier for the new document. Must be unique within the organization. Auto-generated when omitted." + } + ] }, - "path": { + "modelId": { "type": "string", - "description": "Updated URL path segment for the folder (the folder's own segment only)" - } - }, - "required": [ - "id", - "name", - "path" - ] - }, - "FoldersUpdateBody": { - "type": "object", - "properties": { + "format": "uuid", + "description": "Base workbook model the document is built on — a SHARED model, or a SHARED_EXTENSION with `allowAsWorkbookBase = true`." + }, "name": { "type": "string", "minLength": 1, - "description": "New display name for the folder", - "example": "Q1 Reports" + "maxLength": 254, + "description": "Document name." }, - "path": { - "type": "string", - "minLength": 1, - "pattern": "^[a-zA-Z0-9-]+$", - "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", - "example": "q1-reports" + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsPatchExternal" }, - "resolvePathConflict": { - "type": "boolean", - "default": false, - "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." - } - } - }, - "FoldersGetPermissionsResponse": { - "type": "object", - "properties": { - "permits": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "description": "Whether access boost is enabled for this permit" - }, - "role": { - "type": "string", - "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", - "example": "VIEWER" - }, - "userGroupId": { - "type": "string", - "description": "User group ID if this is a group permit" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID if this is a user permit" - } - }, - "required": [ - "role" - ] - }, - "description": "List of permission permits for the folder" - } - }, - "required": [ - "permits" - ] - }, - "FoldersAddPermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were added successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersAddPermissionsBody": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "default": false, - "description": "Whether to grant access boost" + "settings": { + "$ref": "#/components/schemas/SettingsPatchExternal" }, - "role": { + "summary": { "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" - ], - "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", - "example": "VIEWER" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to grant permission to" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to grant permission to" + "minLength": 1, + "maxLength": 255, + "description": "Caller-supplied note describing the create, written to the history audit trail. Defaults to \"Created document\" when omitted." } }, "required": [ - "role" + "modelId", + "name" ], "additionalProperties": false }, - "FoldersUpdatePermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were updated successfully" - } + "Containers": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/PageContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + } + ] }, - "required": [ - "success" - ] + "description": "Container layout array (grid / stack / page / reference containers, recursively nested). The server validates the full structure on apply." }, - "FoldersUpdatePermissionsBody": { + "GridContainer": { "type": "object", "properties": { - "accessBoost": { - "type": "boolean", - "description": "Whether to grant access boost" + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" }, - "role": { + "instanceKey": { "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" - ], - "description": "New content role to assign" + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to update permissions for" + "name": { + "type": "string", + "description": "Human-readable name for the container, used for easier reference in logic and design" }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to update permissions for" - } - }, - "additionalProperties": false - }, - "FoldersRevokePermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were revoked successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersRevokePermissionsBody": { - "type": "object", - "properties": { - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to revoke permissions from" + "aspectRatio": { + "type": "string" }, - "userIds": { + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + }, + "after": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "before": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "children": { "type": "array", "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to revoke permissions from" - } - }, - "additionalProperties": false - }, - "LabelsListResponse": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + "anyOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/ReferenceContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" + { + "allOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + { + "allOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" + { + "allOf": [ + { + "anyOf": [ + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "as": { + "type": "string", + "enum": [ + "chart", + "result", + "ai", + "metadata" + ], + "description": "Render mode: \"chart\" for visualization, \"result\" for data table, \"ai\" for AI summary, \"metadata\" for query metadata" + }, + "format": { + "type": "string", + "enum": [ + "subtitle", + "description", + "name" + ], + "description": "Display format when as is \"ai\" or \"metadata\": \"name\" (metadata only), \"subtitle\", or \"description\"" + }, + "id": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "The query presentation ID this content item references" + }, + "name": { + "type": "string", + "description": "Display name for this query item" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "inline" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tooltip" + ] + } + }, + "required": [ + "as" + ] + } + ], + "description": "Display mode: \"inline\" renders directly, \"tooltip\" shows on hover" + }, + "content": { + "type": "string", + "description": "The text content to display (supports markdown)" + }, + "name": { + "type": "string", + "description": "Display name for this text item (e.g., title, subtitle)" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "textAlign": { + "type": "string", + "enum": [ + "start", + "center", + "end" + ], + "description": "Text alignment: \"start\", \"center\", or \"end\"" + }, + "type": { + "type": "string", + "enum": [ + "inline-text" + ] + } + }, + "required": [ + "instanceKey", + "content", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tabs" + ] + }, + "variant": { + "type": "string", + "enum": [ + "underline", + "bordered" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "buttons" + ] + }, + "variant": { + "type": "string", + "enum": [ + "segment", + "toggle", + "pills" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "list" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "dropdown" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + } + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "includeControls": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uri": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "inline-page-switcher" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the rich text content block" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "control" + ] + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "filter" + ] + }, + "appearance": { + "type": "object", + "properties": { + "control": { + "type": "string", + "enum": [ + "buttonToggle", + "dropdown" + ] + }, + "display": { + "type": "string", + "enum": [ + "inline", + "popover" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "instanceKey", + "type" + ], + "additionalProperties": {} + } + ] + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" ] - }, - "description": "List of labels" - } - }, - "required": [ - "labels" - ] - }, - "LabelsCreateResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + } }, - "name": { + "containerType": { "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + "enum": [ + "grid" + ] }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsCreateBody": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "default": null, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "default": null, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "default": false, - "description": "Show label on homepage. Requires admin permissions." - }, - "name": { - "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" - }, - "verified": { - "type": "boolean", - "default": false, - "description": "Mark as verified label. Requires admin permissions." - } - }, - "required": [ - "name" - ] - }, - "LabelsGetResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsUpdateResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsUpdateBody": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Show label on homepage. Requires admin permissions to modify." + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number", + "description": "Height in grid units (default: 36 for charts)" + }, + "w": { + "type": "number", + "description": "Width in grid columns on a 24-column grid. Common widths: 24 (full), 12 (half), 8 (third), 6 (quarter). x + w must not exceed 24." + }, + "x": { + "type": "number", + "description": "X position on a 24-column grid (0=left edge, 12=middle). Items side-by-side share the same y with complementary x values." + }, + "y": { + "type": "number", + "description": "Y position in grid units (0=top, higher values=lower on page)" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] }, - "name": { - "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" + "metadata": { + "type": "object", + "properties": { + "attachedQueryKey": { + "type": "string", + "description": "Set by the auto-add-tile flow when this container was generated for a specific workbook tab. The server removes containers with a matching `attachedQueryKey` when that tab is deleted. The reducer clears this when the user adds unrelated content (a different query, filter, text tile, page switcher, or sub-container)." + } + }, + "description": "Optional bookkeeping for this container (e.g. `attachedQueryKey` for auto-placed tiles)" }, - "verified": { - "type": "boolean", - "description": "Mark as verified label. Requires admin permissions to modify." - } - } - }, - "ModelsListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "allOf": [ + "padding": { + "anyOf": [ { - "$ref": "#/components/schemas/PageInfo" + "type": "number", + "enum": [ + 0 + ] }, { - "description": "Pagination information" - } - ] - }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseModelId": { - "type": [ - "string", - "null" - ], - "description": "Base model ID for branch/extension models" - }, - "branches": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Branch ID" - }, - "name": { - "type": "string", - "description": "Branch name" - } - }, - "required": [ - "id", - "name" - ] - }, - "description": "Active branches (if include=activeBranches)" - }, - "connectionId": { - "type": [ - "string", - "null" - ], - "description": "Connection ID" - }, - "createdAt": { - "type": "string", - "description": "Creation timestamp" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Deletion timestamp" - }, - "id": { - "type": "string", - "description": "Model ID" - }, - "modelKind": { - "type": [ - "string", - "null" - ], - "description": "Model kind" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Model name" - }, - "updatedAt": { - "type": "string", - "description": "Last update timestamp" - } + "type": "number", + "enum": [ + 0.5 + ] }, - "required": [ - "baseModelId", - "connectionId", - "createdAt", - "deletedAt", - "id", - "modelKind", - "name", - "updatedAt" - ] - }, - "description": "List of model records" - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "CreateModelSchemaBase": { - "type": "object", - "properties": { - "accessGrants": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoostable": { - "type": "boolean" - }, - "allowedValues": { - "type": "array", - "items": { - "type": "string" - } - }, - "codeComments": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "ignored": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "userAttribute": { - "type": "string" - } + { + "type": "number", + "enum": [ + 1 + ] }, - "required": [ - "accessBoostable", - "name" - ] - }, - "description": "Access grants for the model" - }, - "allowAsWorkbookBase": { - "type": "boolean", - "description": "Allow this model as a workbook base" - }, - "baseModelId": { - "type": "string", - "description": "Base model ID for extension or branch models" - }, - "connectionId": { - "type": "string", - "description": "Connection ID for the model" - }, - "modelKind": { - "anyOf": [ { - "type": "string", + "type": "number", "enum": [ - "SCHEMA" + 2 ] }, { - "type": "string", + "type": "number", "enum": [ - "SHARED" + 3 ] }, { - "type": "string", + "type": "number", "enum": [ - "SHARED_EXTENSION" + 4 ] }, { - "type": "string", + "type": "number", "enum": [ - "BRANCH" + 5 ] - } - ], - "default": "SCHEMA", - "description": "Kind of model to create" - }, - "modelName": { - "type": "string", - "description": "Name for the model" - }, - "usesIsolatedBranches": { - "type": "boolean", - "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" - } - }, - "required": [ - "connectionId" - ] - }, - "ModelsUpdateResponse": { - "type": "object", - "properties": { - "model": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Model ID" }, - "name": { - "type": "string", - "description": "Updated model name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Updated model details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - } - }, - "required": [ - "model", - "success" - ] - }, - "ModelsUpdateBody": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "New name for the model", - "example": "My Renamed Model" - } - }, - "required": [ - "name" - ] - }, - "JobsGetStatusResponse": { - "type": "object", - "properties": { - "job_id": { - "type": "string", - "description": "The job ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "job_type": { - "type": "string", - "description": "The type of job (e.g., REFRESH_SCHEMA)", - "example": "REFRESH_SCHEMA" - }, - "status": { - "type": "string", - "enum": [ - "IN_PROGRESS", - "COMPLETED", - "FAILED" - ], - "description": "Current status of the job", - "example": "COMPLETED" - } - }, - "required": [ - "job_id", - "job_type", - "status" - ] - }, - "ModelsGetSchemasResponse": { - "type": "object", - "properties": { - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" - } - }, - "required": [ - "schemas" - ] - }, - "ModelsGetViewResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "views": { - "type": "array", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string", - "description": "View description" - }, - "fields": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Field name" + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] }, - "type": { - "type": "string", + { + "type": "number", "enum": [ - "dimension", - "measure", - "filter" - ], - "description": "Field type" + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] } - }, - "required": [ - "name", - "type" ] }, - "description": "Fields in the view" - }, - "hidden": { - "type": "boolean", - "description": "Whether the view is hidden" - }, - "label": { - "type": "string", - "description": "View label" - }, - "name": { - "type": "string", - "description": "View name" - } + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] }, - "required": [ - "fields", - "name" - ] - }, - "description": "List of views" - } - }, - "required": [ - "success", - "views" - ] - }, - "ModelsUpdateViewBody": { - "type": "object", - "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the view" - }, - "description": { - "type": "string", - "description": "View description" - }, - "format": { - "type": "string", - "description": "View format" - }, - "hidden": { - "type": "boolean", - "description": "Whether the view is hidden" - }, - "label": { - "type": "string", - "description": "View label" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the view" - } - } - }, - "ModelsUpdateFieldBody": { - "type": "object", - "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "allValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Deprecated: use sampleValues instead" - }, - "binBoundaries": { - "type": "array", - "items": { - "type": "number" - }, - "description": "Bin boundaries for binned fields" - }, - "binLabels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels for bins" - }, - "description": { - "type": "string", - "description": "Field description" - }, - "drillFields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Drill-down fields" - }, - "elseValue": { - "type": "string", - "description": "Else value for grouped fields" - }, - "filters": { - "type": "object", - "additionalProperties": {}, - "description": "Filters for the field" - }, - "format": { - "type": "string", - "description": "Field format" - }, - "groupFilters": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Group filters" - }, - "groupLabel": { - "type": "string", - "description": "Group label" - }, - "groupNames": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Group names" - }, - "hidden": { - "type": "boolean", - "description": "Whether the field is hidden" - }, - "ignored": { - "type": "boolean", - "description": "Whether the field is ignored" - }, - "isCalc": { - "type": "boolean", - "description": "Whether this is a calculation field" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "newFieldName": { - "type": "string", - "description": "New field name (for rename)" - }, - "newViewName": { - "type": "string", - "description": "New view name (for move)" - }, - "sampleValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Sample values for the field" - }, - "sql": { - "type": "string", - "description": "SQL expression for the field" - }, - "synonyms": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Synonyms for the field" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" - }, - "topicContext": { - "type": "string", - "description": "Topic context for the field" - } - } - }, - "ModelsListTopicsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "topics": { - "type": "array", - "items": { - "type": "object", - "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" - }, - "description": { - "type": "string", - "description": "Topic description" - }, - "group_label": { - "type": "string", - "description": "Group label" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "name": { - "type": "string", - "description": "Topic name" - } - }, - "required": [ - "base_view_name", - "name" - ] - }, - "description": "List of topics" - } - }, - "required": [ - "success", - "topics" - ] - }, - "ModelsGetTopicResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "topic": { - "type": "object", - "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" - }, - "description": { - "type": "string", - "description": "Topic description" - }, - "group_label": { - "type": "string", - "description": "Group label" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "name": { - "type": "string", - "description": "Topic name" - }, - "relationships": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Relationships for the topic" - }, - "views": { + { "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Views available in the topic" - } - }, - "required": [ - "base_view_name", - "name", - "relationships", - "views" - ], - "description": "Topic details with relationships and views" - } - }, - "required": [ - "success", - "topic" - ] - }, - "ModelsUpdateTopicBody": { - "type": "object", - "properties": { - "description": { - "type": "string", - "description": "Topic description" - }, - "groupLabel": { - "type": "string", - "description": "Group label for the topic" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "newTopicName": { - "type": "string", - "description": "New topic name (for rename)" - } - } - }, - "ModelsCreateFieldBody": { - "type": "object", - "properties": { - "aggregateType": { - "type": "string", - "description": "Aggregate type for measures" - }, - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "description": { - "type": "string", - "description": "Field description" - }, - "fieldName": { - "type": "string", - "description": "Field name", - "example": "total_revenue" - }, - "format": { - "type": "string", - "description": "Field format" - }, - "hidden": { - "type": "boolean", - "description": "Whether the field is hidden" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "sql": { - "type": "string", - "description": "SQL expression for the field" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" - }, - "topicContext": { - "type": "string", - "description": "Topic context for topic-scoped fields" - }, - "viewName": { - "type": "string", - "description": "View to add the field to", - "example": "orders" - } - }, - "required": [ - "fieldName", - "viewName" - ] - }, - "ModelsRefreshResponse": { - "type": "object", - "properties": { - "jobId": { - "type": "string", - "description": "Job ID for the refresh operation" - }, - "modelId": { - "type": "string", - "description": "Model ID being refreshed" - }, - "status": { - "type": "string", - "enum": [ - "running", - "completed", - "failed" - ], - "description": "Current status of the refresh" - } - }, - "required": [ - "jobId", - "modelId", - "status" - ] - }, - "ModelsValidateResponse": { - "type": "object", - "properties": { - "issues": { - "type": "array", - "items": { - "type": "object", - "properties": { - "field": { - "type": "string", - "description": "Field name with the issue" - }, - "message": { - "type": "string", - "description": "Validation issue message" - }, - "severity": { - "type": "string", - "enum": [ - "error", - "warning" - ], - "description": "Issue severity" - }, - "view": { - "type": "string", - "description": "View name with the issue" - } + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] }, - "required": [ - "message", - "severity" - ] - }, - "description": "List of validation issues" - }, - "valid": { - "type": "boolean", - "description": "Whether the model is valid" - } - }, - "required": [ - "issues", - "valid" - ] - }, - "ModelsMigrateBody": { - "type": "object", - "properties": { - "branchName": { - "type": "string", - "description": "Branch name for the target model" - }, - "commitMessage": { - "type": "string", - "description": "Commit message for git sync" - }, - "gitRef": { - "type": "string", - "description": "Git reference" - }, - "targetModelId": { - "type": "string", - "format": "uuid", - "description": "Target model ID to migrate to" - } - }, - "required": [ - "targetModelId" - ] - }, - "ModelsDbtExposuresResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtExposureWithMeta" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "DbtExposureWithMeta": { - "type": "object", - "properties": { - "dashboard_identifier": { - "type": "string", - "description": "Identifier of the dashboard that generated this exposure" + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + } + ] }, - "deduplication_name": { + "style": { "type": "string", - "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." - }, - "exposure": { - "$ref": "#/components/schemas/DbtExposure" + "pattern": "^[a-z0-9-]+$" } }, "required": [ - "dashboard_identifier", - "deduplication_name", - "exposure" - ] + "instanceKey", + "children", + "containerType" + ], + "description": "Grid container — children are positioned on a grid (each carries a gridPosition)." }, - "DbtExposure": { + "StackContainer": { "type": "object", "properties": { - "depends_on": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of dbt model references (e.g. ref('model_name'))", - "example": [ - "ref('orders')", - "ref('customers')" - ] + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" }, - "label": { + "instanceKey": { "type": "string", - "description": "Original dashboard name" + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." }, "name": { "type": "string", - "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", - "example": "my_dashboard" + "description": "Human-readable name for the container, used for easier reference in logic and design" }, - "owner": { - "$ref": "#/components/schemas/DbtExposureOwner" + "aspectRatio": { + "type": "string" }, - "type": { + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + }, + "after": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "align": { "type": "string", "enum": [ - "dashboard", - "notebook", - "analysis", - "ml", - "application" + "flex-start", + "flex-end", + "center", + "stretch" ], - "description": "Type of the exposure", - "example": "dashboard" - }, - "url": { - "type": "string", - "description": "URL of the dashboard" - } - }, - "required": [ - "depends_on", - "name", - "owner", - "type" - ], - "description": "The dbt exposure for this dashboard." - }, - "DbtExposureOwner": { - "type": "object", - "properties": { - "email": { - "type": "string", - "description": "Email of the dashboard owner" - }, - "name": { - "type": "string", - "description": "Name of the dashboard owner" - } - }, - "required": [ - "email", - "name" - ] - }, - "ModelsBranchDbtBody": { - "type": "object", - "properties": { - "dbt_environment_id": { - "type": "string", - "format": "uuid", - "description": "ID of the dbt environment to activate on this branch", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "dbt_git_branch": { - "type": "string", - "description": "Git branch to associate with the dbt environment", - "example": "feature/new-metrics" - } - }, - "required": [ - "dbt_environment_id" - ] - }, - "ModelsMergeBranchResponse": { - "type": "object", - "properties": { - "failed_drafts_count": { - "type": "number", - "description": "Number of drafts that failed to publish" - }, - "git_synced": { - "type": "boolean", - "description": "Whether git was synced" - }, - "published_drafts_count": { - "type": "number", - "description": "Number of drafts published" - }, - "success": { - "type": "boolean", - "description": "Whether the merge succeeded" - } - }, - "required": [ - "failed_drafts_count", - "git_synced", - "published_drafts_count", - "success" - ] - }, - "ModelsMergeBranchBody": { - "type": "object", - "properties": { - "commit_message": { - "type": "string", - "description": "Custom commit message for git sync" - }, - "delete_branch": { - "type": "boolean", - "default": false, - "description": "Delete the branch after merging" - }, - "force_override_git_settings": { - "type": "boolean", - "default": false, - "description": "Override PR-required or git-follower settings" - }, - "publish_drafts": { - "type": "boolean", - "default": true, - "description": "Publish branch-attached drafts" - } - } - }, - "ModelsCommitResponse": { - "type": "object", - "properties": { - "did_sync": { - "type": "boolean", - "description": "Whether a sync operation was performed against git" - }, - "git_sha": { - "type": [ - "string", - "null" - ], - "description": "The git SHA of the commit that was pushed (null if no commit was needed)" - }, - "in_sync": { - "type": "boolean", - "description": "Whether the branch is in sync with git after the operation" - }, - "pr_url": { - "type": [ - "string", - "null" - ], - "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." - } - }, - "required": [ - "did_sync", - "git_sha", - "in_sync", - "pr_url" - ] - }, - "ModelsCommitBody": { - "type": "object", - "properties": { - "allow_branch_exists": { - "type": "boolean", - "default": true, - "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", - "example": true - }, - "branch_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to commit.", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "commit_message": { - "type": "string", - "minLength": 1, - "description": "Commit message for the git commit.", - "example": "Add new orders view" + "description": "Cross-axis alignment of children (e.g., center, stretch)" }, - "require_branch_exists": { - "type": "boolean", - "default": false, - "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", - "example": false - } - }, - "required": [ - "branch_id", - "commit_message" - ] - }, - "ModelsCacheResetResponse": { - "type": "object", - "properties": { - "cache_reset": { - "type": "object", - "properties": { - "created_at": { - "type": [ - "string", - "null" - ], - "description": "Creation timestamp" - }, - "model_id": { - "type": "string", - "description": "Model ID" - }, - "policy_name": { - "type": "string", - "description": "Cache policy name" - }, - "reset_at": { - "type": [ - "string", - "null" - ], - "description": "Reset timestamp" + "before": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" }, - "updated_at": { - "type": [ - "string", - "null" - ], - "description": "Last update timestamp" + { + "$ref": "#/components/schemas/ReferenceContainer" } - }, - "required": [ - "created_at", - "model_id", - "policy_name", - "reset_at", - "updated_at" - ], - "description": "Cache reset details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - } - }, - "required": [ - "cache_reset", - "success" - ] - }, - "ModelsCacheResetBody": { - "type": "object", - "properties": { - "resetAt": { - "type": "string", - "description": "ISO-8601 timestamp for when to reset the cache", - "example": "2024-01-15T12:00:00Z" - } - } - }, - "ModelsGitGetResponse": { - "type": "object", - "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false + ] }, - "cloneUrl": { + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "as": { + "type": "string", + "enum": [ + "chart", + "result", + "ai", + "metadata" + ], + "description": "Render mode: \"chart\" for visualization, \"result\" for data table, \"ai\" for AI summary, \"metadata\" for query metadata" + }, + "format": { + "type": "string", + "enum": [ + "subtitle", + "description", + "name" + ], + "description": "Display format when as is \"ai\" or \"metadata\": \"name\" (metadata only), \"subtitle\", or \"description\"" + }, + "id": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "The query presentation ID this content item references" + }, + "name": { + "type": "string", + "description": "Display name for this query item" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "inline" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tooltip" + ] + } + }, + "required": [ + "as" + ] + } + ], + "description": "Display mode: \"inline\" renders directly, \"tooltip\" shows on hover" + }, + "content": { + "type": "string", + "description": "The text content to display (supports markdown)" + }, + "name": { + "type": "string", + "description": "Display name for this text item (e.g., title, subtitle)" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "textAlign": { + "type": "string", + "enum": [ + "start", + "center", + "end" + ], + "description": "Text alignment: \"start\", \"center\", or \"end\"" + }, + "type": { + "type": "string", + "enum": [ + "inline-text" + ] + } + }, + "required": [ + "instanceKey", + "content", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tabs" + ] + }, + "variant": { + "type": "string", + "enum": [ + "underline", + "bordered" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "buttons" + ] + }, + "variant": { + "type": "string", + "enum": [ + "segment", + "toggle", + "pills" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "list" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "dropdown" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + } + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "includeControls": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uri": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "inline-page-switcher" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the rich text content block" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "control" + ] + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "filter" + ] + }, + "appearance": { + "type": "object", + "properties": { + "control": { + "type": "string", + "enum": [ + "buttonToggle", + "dropdown" + ] + }, + "display": { + "type": "string", + "enum": [ + "inline", + "popover" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "instanceKey", + "type" + ], + "additionalProperties": {} + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + }, + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + } + ] + } + }, + "containerType": { + "type": "string", + "enum": [ + "stack" + ], + "description": "Stack containers lay out children sequentially in a direction (column or row)" + }, + "direction": { + "type": "string", + "enum": [ + "column", + "row" + ], + "description": "Layout direction: \"row\" lays out horizontally, \"column\" stacks vertically (default if not specified)" + }, + "gap": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "number", + "enum": [ + 9 + ] + }, + { + "type": "number", + "enum": [ + 10 + ] + }, + { + "type": "number", + "enum": [ + 11 + ] + }, + { + "type": "number", + "enum": [ + 12 + ] + }, + { + "type": "number", + "enum": [ + 13 + ] + }, + { + "type": "number", + "enum": [ + 14 + ] + }, + { + "type": "number", + "enum": [ + 15 + ] + }, + { + "type": "number", + "enum": [ + 16 + ] + } + ], + "description": "Space between children (CSS size value)" + }, + "justify": { + "type": "string", + "enum": [ + "flex-start", + "flex-end", + "center", + "space-between" + ], + "description": "Main-axis alignment of children (e.g., start, center, end)" + }, + "metadata": { + "type": "object", + "properties": { + "attachedQueryKey": { + "type": "string", + "description": "Set by the auto-add-tile flow when this container was generated for a specific workbook tab. The server removes containers with a matching `attachedQueryKey` when that tab is deleted. The reducer clears this when the user adds unrelated content (a different query, filter, text tile, page switcher, or sub-container)." + } + }, + "description": "Optional bookkeeping for this container (e.g. `attachedQueryKey` for auto-placed tiles)" + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + } + ] + }, + "style": { + "type": "string", + "pattern": "^[a-z0-9-]+$" + }, + "wrap": { + "type": "string", + "enum": [ + "nowrap", + "wrap" + ], + "description": "Whether flex items should wrap to new lines (defaults to nowrap if not specified)" + } + }, + "required": [ + "instanceKey", + "children", + "containerType" + ], + "description": "Stack container — an ordered list of nested children (content, grid, stack, or reference)." + }, + "ReferenceContainer": { + "type": "object", + "properties": { + "containerType": { + "type": "string", + "enum": [ + "reference" + ] + }, + "instanceKey": { + "type": "string" + }, + "referenceKey": { + "type": "string" + } + }, + "required": [ + "containerType", + "instanceKey", + "referenceKey" + ], + "description": "Reference container — points at another container in the collection by its instanceKey." + }, + "PageContainer": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" + }, + "instanceKey": { + "type": "string", + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." + }, + "name": { + "type": "string", + "description": "Human-readable name for the container, used for easier reference in logic and design" + }, + "breakpoint": { + "type": "string", + "enum": [ + "desktop", + "mobile" + ] + }, + "container": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "containerType": { + "type": "string", + "enum": [ + "page" + ] + }, + "media": { + "type": "string", + "enum": [ + "screen", + "print" + ] + } + }, + "required": [ + "instanceKey", + "container", + "containerType" + ], + "description": "Page container — a top-level page wrapping a single grid, stack, or reference container, optionally per breakpoint/media." + }, + "ControlsPatchExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ControlPatchExternal" + }, + "description": "Controls keyed by control ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete." + }, + "order": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Display order for controls. When present, replaces the existing order." + } + } + }, + "ControlPatchExternal": { + "type": [ + "object", + "null" + ], + "properties": { + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ], + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.)." + }, + "map": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean", + "enum": [ + false + ] + } + ] + }, + "description": "Per-tile field overrides keyed by tab ID. Values are a field name (override) or false (exclude tile from control)." + } + }, + "required": [ + "config" + ] + }, + "JsonValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/components/schemas/JsonValue" + }, + { + "type": "null" + } + ] + } + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/JsonValue" + }, + { + "type": "null" + } + ] + } + } + ], + "description": "Arbitrary JSON value (string, number, boolean, null, object, or array)." + }, + "QueryPresentationsPatchExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/QueryPresentationPatchExternal" + }, + "description": "Query presentations keyed by tab ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete. Capped at 48 entries per patch." + }, + "order": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[1-9][0-9]*$" + }, + "description": "Tab display order. When present, replaces the existing order." + } + } + }, + "QueryPresentationPatchExternal": { + "type": [ + "object", + "null" + ], + "properties": { + "aiConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "description": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "subTitle": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + } + }, + "description": "AI-generated metadata config (subtitle/description auto-generation settings)." + }, + "automaticVis": { + "type": [ + "boolean", + "null" + ], + "description": "When true, the system automatically selects the best visualization type." + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "User-provided tab description." + }, + "editingModelObjectName": { + "type": [ + "string", + "null" + ], + "description": "Model object (view/topic) currently being edited via the dataset/query-view editor. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "editingModelObjectNameChange": { + "type": [ + "string", + "null" + ], + "description": "Pending rename of the model object being edited. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter field names controlling display order on this tab." + }, + "isSql": { + "type": [ + "boolean", + "null" + ], + "description": "Whether this tab is in raw SQL mode." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "User-provided tab name." + }, + "prefersChart": { + "type": "boolean", + "description": "When true, the chart view is shown by default instead of the data table." + }, + "query": { + "type": [ + "object", + "null" + ], + "properties": { + "aiGenerated": { + "type": "boolean", + "description": "True when AI generated this query’s SQL; the AI SQL is shown in the advanced SQL box." + }, + "branch_id": { + "type": "string", + "description": "Branch model ID when querying against a model branch." + }, + "calculations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allow_refs_to_unselected_fields": { + "type": "boolean", + "description": "Set by the Kotlin parser when this calc references fields not selected at the top level (AI SQL-gen produces these; UI-authored calcs do not)." + }, + "calc_name": { + "type": "string", + "description": "Internal identifier for the calculation, used as the column alias." + }, + "description": { + "type": "string", + "description": "Description of the calculation." + }, + "format": { + "type": "string", + "description": "Number/date format string (e.g. \"#,##0.00\")." + }, + "label": { + "type": "string", + "description": "Display label shown in the UI." + }, + "original_formula": { + "type": "string", + "description": "The original Excel-style formula before parsing (e.g. \"=SUM(A1:A10)\")." + }, + "outside_pivot": { + "type": "boolean", + "description": "When true, the calculation is evaluated outside the pivot grouping." + }, + "pushdown": { + "type": [ + "boolean", + "null" + ], + "description": "Per-calc override for whether to evaluate before the row limit. `null` defers to the model-level default." + }, + "sql": { + "type": "string", + "description": "Compiled SQL string produced from the formula." + }, + "sql_expression": { + "description": "Parsed SQL expression tree (serialized)." + }, + "swallow_errors": { + "type": "boolean", + "description": "When true, calculation errors are silently swallowed instead of surfaced." + } + }, + "required": [ + "calc_name" + ], + "additionalProperties": {} + }, + "description": "Table calculations attached to this query." + }, + "column_limit": { + "type": "number", + "description": "Max number of pivot columns to return." + }, + "column_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Column-level aggregation totals, keyed by field name." + }, + "controls": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ] + }, + "description": "Interactive controls (field selectors, PoP controls) attached to this query." + }, + "cube_metadata": { + "type": "object", + "properties": { + "cube_name": { + "type": "string" + }, + "hash_key": { + "type": "string" + }, + "topic_name": { + "type": "string" + } + }, + "required": [ + "cube_name", + "hash_key", + "topic_name" + ], + "additionalProperties": {}, + "description": "Cube-specific metadata (topic name, cube name, hash key) for cube-backed queries." + }, + "custom_summary_types": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Per-field custom summary functions (e.g. SUM, AVG, COUNT)." + }, + "dbtFileName": { + "type": "string", + "description": "dbt file name when this query is backed by a dbt model." + }, + "dbtMode": { + "type": "boolean", + "description": "Whether this query is in dbt mode." + }, + "default_group_by": { + "type": "boolean", + "description": "When true, all dimensions are implicitly included in GROUP BY." + }, + "dimensionIndex": { + "type": "number", + "description": "Index of the primary dimension used for result ordering." + }, + "executableSQL": { + "type": "string", + "description": "Server-compiled SQL string (read-only, set by the backend)." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Model field names selected for the query (dimensions + measures)." + }, + "fill_fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Fields whose missing date/time values should be filled with nulls to create continuous series." + }, + "filters": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Query filters keyed by filter ID." + }, + "filtersUsedInSql": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Filters that were embedded directly in raw SQL (read-only)." + }, + "join_paths_from_topic_name": { + "type": "string", + "description": "Topic name that determines join path precedence for parsed SQL queries." + }, + "join_via_map": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "Virtual topic join path overrides, keyed by view name to ordered join path." + }, + "limit": { + "type": "number", + "description": "Row limit for the query." + }, + "manualSort": { + "type": "boolean", + "description": "When true, the user has explicitly set a custom sort order." + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "label": { + "type": "string" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": {} + }, + "description": "Per-field display metadata (format, label, order)." + }, + "offset": { + "type": "number", + "description": "Row offset for pagination." + }, + "parsed": { + "type": "boolean", + "description": "Whether this raw SQL query has been parsed into a semantic query." + }, + "periodOverPeriodTransposed": { + "type": "boolean", + "description": "Whether the period-over-period comparison columns are transposed." + }, + "period_over_period_computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date_filter_field_name": { + "type": "string", + "description": "The date dimension field this comparison is anchored to." + }, + "date_filter_id": { + "type": "string", + "description": "ID of the date filter being offset (if backed by a dashboard filter)." + }, + "is_dynamic_previous_period": { + "type": "boolean", + "description": "When true, the previous period is calculated dynamically relative to the current filter range." + }, + "periods_ago": { + "type": [ + "number", + "null" + ], + "description": "How many periods back to compare (e.g. 1 = previous period). Null if not set." + }, + "time_unit_name": { + "type": [ + "string", + "null" + ], + "description": "Time grain for the offset (e.g. \"month\", \"year\"). Null if not set." + } + }, + "required": [ + "date_filter_field_name", + "periods_ago", + "time_unit_name" + ], + "additionalProperties": {} + }, + "description": "Period-over-period comparison configurations." + }, + "pivots": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names to pivot on (columns become values)." + }, + "rewriteSql": { + "type": "boolean", + "description": "When true, the backend should rewrite/optimize the SQL." + }, + "row_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Row-level aggregation totals, keyed by field name." + }, + "sorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "column_name": { + "type": "string", + "description": "The model field name to sort by." + }, + "is_column_sort": { + "type": "boolean", + "description": "When true, this sort targets a pivoted column rather than a row dimension." + }, + "pivot_value_map": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ] + }, + "description": "Maps pivot field names to specific pivot values, scoping the sort to a single pivot column." + }, + "sort_descending": { + "type": "boolean", + "description": "When true, sort order is descending." + }, + "subtotal_sort": { + "type": "string", + "description": "Field name whose subtotal row should be used as the sort key." + } + }, + "required": [ + "column_name", + "sort_descending" + ], + "additionalProperties": {} + }, + "description": "Sort clauses applied to the query result set." + }, + "sqlSortsEnabled": { + "type": "boolean", + "description": "Whether user-created sorts are enabled on a raw SQL query." + }, + "staticQueryReferences": { + "type": "object", + "additionalProperties": {}, + "description": "Pre-computed query references for AI chat context. Inner shape is `OmniQuery & { model_id: string }`; left as `unknown` to avoid a recursive zod schema. Validated structurally by consumers when they execute the referenced sub-queries." + }, + "table": { + "type": "string", + "description": "Base view (table) name in the model." + }, + "transposed_measures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Measure field names that have been transposed into rows." + }, + "userEditedSQL": { + "type": "string", + "description": "User-authored raw SQL (empty string when not in SQL mode)." + }, + "version": { + "type": "number", + "description": "Schema version for migration support." + } + }, + "required": [ + "calculations", + "column_totals", + "fields", + "fill_fields", + "filters", + "pivots", + "row_totals", + "sorts", + "table", + "userEditedSQL" + ], + "additionalProperties": {}, + "description": "The semantic query for this tab, minus the server-owned workbook model anchors (modelId / model_extension_id). Omitted on a no-op replay; the server anchors new/changed tiles to the draft." + }, + "resultConfig": { + "type": "object", + "additionalProperties": {}, + "description": "Result display configuration (column widths, frozen columns, conditional formatting, number formatting, etc.)." + }, + "subTitle": { + "type": [ + "string", + "null" + ], + "maxLength": 250, + "description": "User-provided tab subtitle." + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "The topic (explore) this query is built on." + }, + "type": { + "type": "string", + "enum": [ + "blank", + "csv", + "query", + "dataset", + "spreadsheet", + "sql", + "dbt", + "query-view", + "linked", + "app" + ], + "description": "The query presentation type (e.g. SEMANTIC, SQL, LINKED, SPREADSHEET)." + }, + "visConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "chartType": { + "type": [ + "string", + "null" + ], + "enum": [ + "auto", + "area", + "areaStacked", + "areaStackedPercentage", + "bar", + "barLine", + "barGrouped", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "regionMap", + "markdown", + "omni-ai-summary-markdown", + "pie", + "funnel", + "sankey", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "singleRecord", + "omni-spreadsheet", + "summaryValue", + "svgMap", + "table", + null + ], + "description": "High-level chart type (e.g. \"bar\", \"line\", \"area\")." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names used in the visualization axes/series." + }, + "version": { + "type": "number", + "description": "Schema version for vis config migration." + }, + "visConfig": { + "type": "object", + "properties": { + "visType": { + "type": [ + "string", + "null" + ], + "enum": [ + "vegalite", + "omni-ai-summary-markdown", + "basic", + "omni-kpi", + "map", + "omni-markdown", + "funnel", + "sankey", + "single-record", + "svg-map", + "omni-spreadsheet", + "spreadsheet-tab", + "summary-value", + "omni-table", + "app", + null + ], + "description": "The visualization type (e.g. \"basic\", \"omni-table\")." + } + }, + "additionalProperties": {}, + "description": "Inner visualization config — structure varies by visType." + } + }, + "additionalProperties": {}, + "description": "Visualization configuration for the tile." + }, + "sourceQueryPresentationKey": { + "type": [ + "string", + "null" + ], + "pattern": "^[1-9][0-9]*$", + "description": "For LINKED-type tabs, the record key — the same identifier used as a `queryPresentations.data` key — of the source tile whose query this tab reuses. Null for all other tab types. This is a tile record key, NOT a positional index into `order`." + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "SettingsPatchExternal": { + "type": "object", + "properties": { + "crossfilterEnabled": { + "type": "boolean", + "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." + }, + "customText": { + "type": [ + "object", + "null" + ], + "properties": { + "queryError": { + "type": "string", + "description": "Custom text shown when a query errors, replacing the default error text." + }, + "queryNoResults": { + "type": "string", + "description": "Custom text shown when a query returns no results, replacing the default empty state." + } + }, + "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." + }, + "facetFilters": { + "type": "boolean", + "description": "When true, dashboard filters are applied per-facet when faceting is active." + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds. Null disables auto-refresh." + }, + "runQueriesOn": { + "type": [ + "string", + "null" + ], + "enum": [ + "current-page", + "all-pages", + null + ], + "description": "Controls whether dashboard queries execute on the visible page or across all pages." + } + }, + "description": "Document settings. Shallow-merged with the existing settings." + }, + "DocumentsV2ReadResponse": { + "type": "object", + "properties": { + "containers": { + "$ref": "#/components/schemas/Containers" + }, + "controls": { + "$ref": "#/components/schemas/ControlsReadExternal" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "name": { + "type": "string", + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsReadExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsReadExternal" + } + }, + "required": [ + "description", + "name", + "queryPresentations" + ] + }, + "ControlsReadExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ControlReadExternal" + }, + "description": "Controls keyed by control ID." + }, + "order": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Display order for controls." + } + }, + "required": [ + "data", + "order" + ] + }, + "ControlReadExternal": { + "type": "object", + "properties": { + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ], + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.)." + }, + "map": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean", + "enum": [ + false + ] + } + ] + }, + "description": "Per-tile field overrides keyed by tab ID. Values are a field name (override) or false (exclude tile from control)." + } + }, + "required": [ + "config" + ] + }, + "QueryPresentationsReadExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/QueryPresentationReadExternal" + }, + "description": "Query presentations keyed by tab ID." + }, + "order": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[1-9][0-9]*$" + }, + "description": "Tab display order." + } + }, + "required": [ + "data", + "order" + ] + }, + "QueryPresentationReadExternal": { + "type": "object", + "properties": { + "aiConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "description": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "subTitle": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + } + }, + "description": "AI-generated metadata config (subtitle/description auto-generation settings)." + }, + "automaticVis": { + "type": [ + "boolean", + "null" + ], + "description": "When true, the system automatically selects the best visualization type." + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "User-provided tab description." + }, + "editingModelObjectName": { + "type": [ + "string", + "null" + ], + "description": "Model object (view/topic) currently being edited via the dataset/query-view editor. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "editingModelObjectNameChange": { + "type": [ + "string", + "null" + ], + "description": "Pending rename of the model object being edited. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter field names controlling display order on this tab." + }, + "isSql": { + "type": [ + "boolean", + "null" + ], + "description": "Whether this tab is in raw SQL mode." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "User-provided tab name." + }, + "prefersChart": { + "type": "boolean", + "description": "When true, the chart view is shown by default instead of the data table." + }, + "query": { + "type": [ + "object", + "null" + ], + "properties": { + "aiGenerated": { + "type": "boolean", + "description": "True when AI generated this query’s SQL; the AI SQL is shown in the advanced SQL box." + }, + "branch_id": { + "type": "string", + "description": "Branch model ID when querying against a model branch." + }, + "calculations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allow_refs_to_unselected_fields": { + "type": "boolean", + "description": "Set by the Kotlin parser when this calc references fields not selected at the top level (AI SQL-gen produces these; UI-authored calcs do not)." + }, + "calc_name": { + "type": "string", + "description": "Internal identifier for the calculation, used as the column alias." + }, + "description": { + "type": "string", + "description": "Description of the calculation." + }, + "format": { + "type": "string", + "description": "Number/date format string (e.g. \"#,##0.00\")." + }, + "label": { + "type": "string", + "description": "Display label shown in the UI." + }, + "original_formula": { + "type": "string", + "description": "The original Excel-style formula before parsing (e.g. \"=SUM(A1:A10)\")." + }, + "outside_pivot": { + "type": "boolean", + "description": "When true, the calculation is evaluated outside the pivot grouping." + }, + "pushdown": { + "type": [ + "boolean", + "null" + ], + "description": "Per-calc override for whether to evaluate before the row limit. `null` defers to the model-level default." + }, + "sql": { + "type": "string", + "description": "Compiled SQL string produced from the formula." + }, + "sql_expression": { + "description": "Parsed SQL expression tree (serialized)." + }, + "swallow_errors": { + "type": "boolean", + "description": "When true, calculation errors are silently swallowed instead of surfaced." + } + }, + "required": [ + "calc_name" + ], + "additionalProperties": {} + }, + "description": "Table calculations attached to this query." + }, + "column_limit": { + "type": "number", + "description": "Max number of pivot columns to return." + }, + "column_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Column-level aggregation totals, keyed by field name." + }, + "controls": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ] + }, + "description": "Interactive controls (field selectors, PoP controls) attached to this query." + }, + "cube_metadata": { + "type": "object", + "properties": { + "cube_name": { + "type": "string" + }, + "hash_key": { + "type": "string" + }, + "topic_name": { + "type": "string" + } + }, + "required": [ + "cube_name", + "hash_key", + "topic_name" + ], + "additionalProperties": {}, + "description": "Cube-specific metadata (topic name, cube name, hash key) for cube-backed queries." + }, + "custom_summary_types": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Per-field custom summary functions (e.g. SUM, AVG, COUNT)." + }, + "dbtFileName": { + "type": "string", + "description": "dbt file name when this query is backed by a dbt model." + }, + "dbtMode": { + "type": "boolean", + "description": "Whether this query is in dbt mode." + }, + "default_group_by": { + "type": "boolean", + "description": "When true, all dimensions are implicitly included in GROUP BY." + }, + "dimensionIndex": { + "type": "number", + "description": "Index of the primary dimension used for result ordering." + }, + "executableSQL": { + "type": "string", + "description": "Server-compiled SQL string (read-only, set by the backend)." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Model field names selected for the query (dimensions + measures)." + }, + "fill_fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Fields whose missing date/time values should be filled with nulls to create continuous series." + }, + "filters": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Query filters keyed by filter ID." + }, + "filtersUsedInSql": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Filters that were embedded directly in raw SQL (read-only)." + }, + "join_paths_from_topic_name": { + "type": "string", + "description": "Topic name that determines join path precedence for parsed SQL queries." + }, + "join_via_map": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "Virtual topic join path overrides, keyed by view name to ordered join path." + }, + "limit": { + "type": "number", + "description": "Row limit for the query." + }, + "manualSort": { + "type": "boolean", + "description": "When true, the user has explicitly set a custom sort order." + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "label": { + "type": "string" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": {} + }, + "description": "Per-field display metadata (format, label, order)." + }, + "offset": { + "type": "number", + "description": "Row offset for pagination." + }, + "parsed": { + "type": "boolean", + "description": "Whether this raw SQL query has been parsed into a semantic query." + }, + "periodOverPeriodTransposed": { + "type": "boolean", + "description": "Whether the period-over-period comparison columns are transposed." + }, + "period_over_period_computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date_filter_field_name": { + "type": "string", + "description": "The date dimension field this comparison is anchored to." + }, + "date_filter_id": { + "type": "string", + "description": "ID of the date filter being offset (if backed by a dashboard filter)." + }, + "is_dynamic_previous_period": { + "type": "boolean", + "description": "When true, the previous period is calculated dynamically relative to the current filter range." + }, + "periods_ago": { + "type": [ + "number", + "null" + ], + "description": "How many periods back to compare (e.g. 1 = previous period). Null if not set." + }, + "time_unit_name": { + "type": [ + "string", + "null" + ], + "description": "Time grain for the offset (e.g. \"month\", \"year\"). Null if not set." + } + }, + "required": [ + "date_filter_field_name", + "periods_ago", + "time_unit_name" + ], + "additionalProperties": {} + }, + "description": "Period-over-period comparison configurations." + }, + "pivots": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names to pivot on (columns become values)." + }, + "rewriteSql": { + "type": "boolean", + "description": "When true, the backend should rewrite/optimize the SQL." + }, + "row_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Row-level aggregation totals, keyed by field name." + }, + "sorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "column_name": { + "type": "string", + "description": "The model field name to sort by." + }, + "is_column_sort": { + "type": "boolean", + "description": "When true, this sort targets a pivoted column rather than a row dimension." + }, + "pivot_value_map": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ] + }, + "description": "Maps pivot field names to specific pivot values, scoping the sort to a single pivot column." + }, + "sort_descending": { + "type": "boolean", + "description": "When true, sort order is descending." + }, + "subtotal_sort": { + "type": "string", + "description": "Field name whose subtotal row should be used as the sort key." + } + }, + "required": [ + "column_name", + "sort_descending" + ], + "additionalProperties": {} + }, + "description": "Sort clauses applied to the query result set." + }, + "sqlSortsEnabled": { + "type": "boolean", + "description": "Whether user-created sorts are enabled on a raw SQL query." + }, + "staticQueryReferences": { + "type": "object", + "additionalProperties": {}, + "description": "Pre-computed query references for AI chat context. Inner shape is `OmniQuery & { model_id: string }`; left as `unknown` to avoid a recursive zod schema. Validated structurally by consumers when they execute the referenced sub-queries." + }, + "table": { + "type": "string", + "description": "Base view (table) name in the model." + }, + "transposed_measures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Measure field names that have been transposed into rows." + }, + "userEditedSQL": { + "type": "string", + "description": "User-authored raw SQL (empty string when not in SQL mode)." + }, + "version": { + "type": "number", + "description": "Schema version for migration support." + } + }, + "required": [ + "calculations", + "column_totals", + "fields", + "fill_fields", + "filters", + "pivots", + "row_totals", + "sorts", + "table", + "userEditedSQL" + ], + "additionalProperties": {}, + "description": "The semantic query for this tab, minus the server-owned workbook model anchors (modelId / model_extension_id). For LINKED-type tabs this field is read-only." + }, + "resultConfig": { + "type": "object", + "additionalProperties": {}, + "description": "Result display configuration (column widths, frozen columns, conditional formatting, number formatting, etc.)." + }, + "subTitle": { + "type": [ + "string", + "null" + ], + "maxLength": 250, + "description": "User-provided tab subtitle." + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "The topic (explore) this query is built on." + }, + "type": { + "type": "string", + "enum": [ + "blank", + "csv", + "query", + "dataset", + "spreadsheet", + "sql", + "dbt", + "query-view", + "linked", + "app" + ], + "description": "The query presentation type (e.g. SEMANTIC, SQL, LINKED, SPREADSHEET)." + }, + "visConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "chartType": { + "type": [ + "string", + "null" + ], + "enum": [ + "auto", + "area", + "areaStacked", + "areaStackedPercentage", + "bar", + "barLine", + "barGrouped", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "regionMap", + "markdown", + "omni-ai-summary-markdown", + "pie", + "funnel", + "sankey", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "singleRecord", + "omni-spreadsheet", + "summaryValue", + "svgMap", + "table", + null + ], + "description": "High-level chart type (e.g. \"bar\", \"line\", \"area\")." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names used in the visualization axes/series." + }, + "version": { + "type": "number", + "description": "Schema version for vis config migration." + }, + "visConfig": { + "type": "object", + "properties": { + "visType": { + "type": [ + "string", + "null" + ], + "enum": [ + "vegalite", + "omni-ai-summary-markdown", + "basic", + "omni-kpi", + "map", + "omni-markdown", + "funnel", + "sankey", + "single-record", + "svg-map", + "omni-spreadsheet", + "spreadsheet-tab", + "summary-value", + "omni-table", + "app", + null + ], + "description": "The visualization type (e.g. \"basic\", \"omni-table\")." + } + }, + "additionalProperties": {}, + "description": "Inner visualization config — structure varies by visType." + } + }, + "additionalProperties": {}, + "description": "Visualization configuration for the tile." + }, + "sourceQueryPresentationKey": { + "type": [ + "string", + "null" + ], + "pattern": "^[1-9][0-9]*$", + "description": "For LINKED-type tabs, the record key — the same identifier used as a `queryPresentations.data` key — of the source tile whose query this tab reuses. Null for all other tab types. This is a tile record key, NOT a positional index into `order`." + } + }, + "required": [ + "aiConfig", + "automaticVis", + "description", + "filterOrder", + "isSql", + "name", + "prefersChart", + "query", + "resultConfig", + "subTitle", + "topicName", + "type", + "visConfig", + "sourceQueryPresentationKey" + ] + }, + "SettingsReadExternal": { + "type": "object", + "properties": { + "crossfilterEnabled": { + "type": "boolean", + "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." + }, + "customText": { + "type": [ + "object", + "null" + ], + "properties": { + "queryError": { + "type": "string", + "description": "Custom text shown when a query errors, replacing the default error text." + }, + "queryNoResults": { + "type": "string", + "description": "Custom text shown when a query returns no results, replacing the default empty state." + } + }, + "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." + }, + "facetFilters": { + "type": "boolean", + "description": "When true, dashboard filters are applied per-facet when faceting is active." + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds. Null disables auto-refresh." + }, + "runQueriesOn": { + "type": [ + "string", + "null" + ], + "enum": [ + "current-page", + "all-pages", + null + ], + "description": "Controls whether dashboard queries execute on the visible page or across all pages." + } + }, + "required": [ + "crossfilterEnabled", + "customText", + "facetFilters", + "refreshInterval", + "runQueriesOn" + ] + }, + "DocumentsV2PatchDraftResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "draftIdentifier": { + "type": "string", + "description": "Identifier of the draft the patch was applied to." + }, + "identifier": { + "type": "string", + "description": "Published document identifier the draft targets." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "draftIdentifier", + "identifier", + "name" + ] + }, + "DocumentsV2CreateDraftBody": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" + }, + { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch the draft is created on. Omit for a draft on the main (unpublished) workspace." + } + }, + "additionalProperties": false + } + ] + }, + "DocumentsV2PatchDraftBody": { + "type": "object", + "properties": { + "containers": { + "allOf": [ + { + "$ref": "#/components/schemas/Containers" + }, + { + "description": "Container layout. When present, fully replaces the existing layout." + } + ] + }, + "controls": { + "$ref": "#/components/schemas/ControlsPatchExternal" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsPatchExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsPatchExternal" + }, + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Caller-supplied description of what this patch changes, written to the history audit trail. When absent, the server generates one from the touched sections." + } + }, + "additionalProperties": false + }, + "DocumentsV2PublishDraftResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "identifier": { + "type": "string", + "description": "Published document identifier." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "identifier", + "name" + ] + }, + "EmbedSsoGenerateSessionResponse": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID to use for embedding Omni content" + } + }, + "required": [ + "sessionId" + ] + }, + "EmbedSsoGenerateSessionBody": { + "type": "object", + "properties": { + "externalId": { + "type": "string", + "description": "External identifier for the user (from your system)", + "example": "user-123" + }, + "groups": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional list of group names to assign to the user", + "example": [ + "engineering", + "sales" + ] + }, + "name": { + "type": "string", + "description": "Display name for the user", + "example": "John Doe" + }, + "userAttributes": { + "type": "object", + "additionalProperties": {}, + "description": "Optional user attributes for row-level security" + } + }, + "required": [ + "externalId", + "name" + ] + }, + "EvalPromptSetsListResponse": { + "type": "object", + "properties": { + "prompt_sets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalPromptSetListItem" + }, + "description": "Prompt sets matching the query, sorted alphabetically by name." + } + }, + "required": [ + "prompt_sets" + ] + }, + "EvalPromptSetListItem": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description of the prompt set.", + "example": "Regression suite for the orders topic" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the prompt set has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "description": "Human-readable name for the prompt set.", + "example": "Orders regression" + }, + "slug": { + "type": "string", + "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", + "example": "orders-regression" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was last updated.", + "example": "2025-01-15T10:00:00.000Z" + }, + "latest_run_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp of the most recent run on this prompt set, if any.", + "example": "2025-01-15T10:05:00.000Z" + }, + "prompt_count": { + "type": "integer", + "description": "Number of prompts in the set.", + "example": 12 + } + }, + "required": [ + "created_at", + "description", + "id", + "is_archived", + "model_id", + "name", + "slug", + "updated_at", + "latest_run_at", + "prompt_count" + ] + }, + "EvalApiError400": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Bad Request: name: Required" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 400 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError401": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Unauthorized: Missing or invalid API key" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 401 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError403": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "AI eval requires at least Querier access on the model" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 403 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError404": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Prompt set not found" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 404 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsCreateResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSet": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description of the prompt set.", + "example": "Regression suite for the orders topic" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the prompt set has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "description": "Human-readable name for the prompt set.", + "example": "Orders regression" + }, + "prompts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalPrompt" + }, + "description": "Prompts that make up the set." + }, + "slug": { + "type": "string", + "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", + "example": "orders-regression" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was last updated.", + "example": "2025-01-15T10:00:00.000Z" + } + }, + "required": [ + "created_at", + "description", + "id", + "is_archived", + "model_id", + "name", + "prompts", + "slug", + "updated_at" + ] + }, + "EvalPrompt": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "expectation": { + "type": [ + "string", + "null" + ], + "description": "The expectation the analysis judge scores the analysis against, or null when none was set.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "prompt_text": { + "type": "string", + "description": "The natural language prompt text the AI is evaluated on.", + "example": "What are the top 5 products by revenue?" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt was last updated.", + "example": "2025-01-15T10:00:00.000Z" + } + }, + "required": [ + "created_at", + "expectation", + "id", + "prompt_text", + "updated_at" + ] + }, + "EvalPromptSetsCreateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "Optional human-readable description of the prompt set. Max 1024 characters.", + "example": "Regression suite for the orders topic" + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Human-readable name for the prompt set. 255 characters or fewer.", + "example": "Orders regression" + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expectation": { + "type": [ + "string", + "null" + ], + "maxLength": 16000, + "description": "Optional expectation the analysis judge scores the analysis against. Max 16000 characters.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "prompt_text": { + "type": "string", + "minLength": 1, + "maxLength": 8000, + "description": "The natural language prompt text. Max 8000 characters.", + "example": "What are the top 5 products by revenue?" + } + }, + "required": [ + "prompt_text" + ] + }, + "maxItems": 25, + "default": [], + "description": "Initial prompts for the set. Defaults to an empty list. At most 25 prompts." + }, + "slug": { + "type": "string", + "maxLength": 255, + "pattern": "^[a-z][a-z0-9-]*$", + "description": "URL-safe identifier for the prompt set. Must be unique per `model_id` and match `^[a-z][a-z0-9-]*$`. Max 255 characters.", + "example": "orders-regression" + } + }, + "required": [ + "model_id", + "name", + "slug" + ] + }, + "EvalPromptSetsGetResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSetsUpdateResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalApiError422": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "A prompt being updated does not belong to this prompt set" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 422 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsUpdateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "New description for the prompt set. Pass `null` to clear. Max 1024 characters." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "New human-readable name for the prompt set. 255 characters or fewer." + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expectation": { + "type": [ + "string", + "null" + ], + "maxLength": 16000, + "description": "Optional expectation the analysis judge scores the analysis against. Pass `null` to clear. Max 16000 characters.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Existing prompt id. When provided, updates that prompt; when omitted, a new prompt is created. Prompts not included in this list are removed." + }, + "prompt_text": { + "type": "string", + "minLength": 1, + "maxLength": 8000, + "description": "Updated or new prompt text. Max 8000 characters.", + "example": "What are the top 10 products by revenue this quarter?" + } + }, + "required": [ + "prompt_text" + ] + }, + "maxItems": 25, + "description": "Full desired set of prompts after the update. Prompts omitted from this list are deleted; new prompts (no `id`) are appended in body order. Existing prompts retain their original position — reordering is not supported on this endpoint. At most 25 prompts total." + } + } + }, + "EvalPromptSetsDeleteResponse": { + "type": "object", + "properties": { + "cancelled_job_count": { + "type": "integer", + "description": "Number of in-flight agentic jobs associated with this prompt set that were cancelled as part of the archive.", + "example": 0 + }, + "is_archived": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always `true` on success — archives the prompt set." + } + }, + "required": [ + "cancelled_job_count", + "is_archived" + ] + }, + "EvalApiError500": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Archive committed but a run-cancellation failed; retry to complete" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 500 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsUnarchiveResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "FoldersListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents in the folder" + }, + "favorites": { + "type": "number", + "description": "Number of users who have favorited this folder" + } + }, + "required": [ + "documents", + "favorites" + ], + "description": "Count statistics for the folder" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique folder identifier" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels associated with the folder" + }, + "name": { + "type": "string", + "description": "Name of the folder", + "example": "My Reports" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" + }, + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "/shared/reports/my-reports" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/my-reports" + } + }, + "required": [ + "id", + "name", + "ownerId", + "path", + "url" + ] + }, + "description": "List of folders" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "FoldersCreateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the created folder" + }, + "name": { + "type": "string", + "description": "Name of the created folder" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" + }, + "path": { + "type": "string", + "description": "Full path to the folder" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope of the folder" + } + }, + "required": [ + "id", + "name", + "ownerId", + "path", + "scope" + ] + }, + "FoldersCreateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Name of the folder to create", + "example": "My New Folder" + }, + "parentFolderId": { + "type": "string", + "format": "uuid", + "description": "Parent folder ID (omit to create at root level)" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope for the folder" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to create the folder as (for org-scoped API keys only)" + } + }, + "required": [ + "name" + ] + }, + "FoldersDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the folder was deleted successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersUpdateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Folder ID" + }, + "name": { + "type": "string", + "description": "Updated folder name" + }, + "path": { + "type": "string", + "description": "Updated URL path segment for the folder (the folder's own segment only)" + } + }, + "required": [ + "id", + "name", + "path" + ] + }, + "FoldersUpdateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "New display name for the folder", + "example": "Q1 Reports" + }, + "path": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z0-9-]+$", + "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", + "example": "q1-reports" + }, + "resolvePathConflict": { + "type": "boolean", + "default": false, + "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." + } + } + }, + "FoldersGetPermissionsResponse": { + "type": "object", + "properties": { + "permits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Whether access boost is enabled for this permit" + }, + "role": { + "type": "string", + "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", + "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "User group ID if this is a group permit" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID if this is a user permit" + } + }, + "required": [ + "role" + ] + }, + "description": "List of permission permits for the folder" + } + }, + "required": [ + "permits" + ] + }, + "FoldersAddPermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were added successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersAddPermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "default": false, + "description": "Whether to grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", + "example": "VIEWER" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to grant permission to" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to grant permission to" + } + }, + "required": [ + "role" + ], + "additionalProperties": false + }, + "FoldersUpdatePermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were updated successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersUpdatePermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Whether to grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "New content role to assign" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to update permissions for" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to update permissions for" + } + }, + "additionalProperties": false + }, + "FoldersRevokePermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were revoked successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersRevokePermissionsBody": { + "type": "object", + "properties": { + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to revoke permissions from" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to revoke permissions from" + } + }, + "additionalProperties": false + }, + "LabelsListResponse": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "description": "List of labels" + } + }, + "required": [ + "labels" + ] + }, + "LabelsCreateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsCreateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "default": null, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "default": null, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "default": false, + "description": "Show label on homepage. Requires admin permissions." + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "default": false, + "description": "Mark as verified label. Requires admin permissions." + } + }, + "required": [ + "name" + ] + }, + "LabelsGetResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Show label on homepage. Requires admin permissions to modify." + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "description": "Mark as verified label. Requires admin permissions to modify." + } + } + }, + "ModelsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseModelId": { + "type": [ + "string", + "null" + ], + "description": "Base model ID for branch/extension models" + }, + "branches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Branch ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ] + }, + "description": "Active branches (if include=activeBranches)" + }, + "connectionId": { + "type": [ + "string", + "null" + ], + "description": "Connection ID" + }, + "createdAt": { + "type": "string", + "description": "Creation timestamp" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Deletion timestamp" + }, + "id": { + "type": "string", + "description": "Model ID" + }, + "modelKind": { + "type": [ + "string", + "null" + ], + "description": "Model kind" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Model name" + }, + "updatedAt": { + "type": "string", + "description": "Last update timestamp" + } + }, + "required": [ + "baseModelId", + "connectionId", + "createdAt", + "deletedAt", + "id", + "modelKind", + "name", + "updatedAt" + ] + }, + "description": "List of model records" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "CreateModelSchemaBase": { + "type": "object", + "properties": { + "accessGrants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoostable": { + "type": "boolean" + }, + "allowedValues": { + "type": "array", + "items": { + "type": "string" + } + }, + "codeComments": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ignored": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "userAttribute": { + "type": "string" + } + }, + "required": [ + "accessBoostable", + "name" + ] + }, + "description": "Access grants for the model" + }, + "allowAsWorkbookBase": { + "type": "boolean", + "description": "Allow this model as a workbook base" + }, + "baseModelId": { + "type": "string", + "description": "Base model ID for extension or branch models" + }, + "connectionId": { + "type": "string", + "description": "Connection ID for the model" + }, + "modelKind": { + "anyOf": [ + { + "type": "string", + "enum": [ + "SCHEMA" + ] + }, + { + "type": "string", + "enum": [ + "SHARED" + ] + }, + { + "type": "string", + "enum": [ + "SHARED_EXTENSION" + ] + }, + { + "type": "string", + "enum": [ + "BRANCH" + ] + } + ], + "default": "SCHEMA", + "description": "Kind of model to create" + }, + "modelName": { + "type": "string", + "description": "Name for the model" + }, + "usesIsolatedBranches": { + "type": "boolean", + "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" + } + }, + "required": [ + "connectionId" + ] + }, + "ModelsUpdateResponse": { + "type": "object", + "properties": { + "model": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Model ID" + }, + "name": { + "type": "string", + "description": "Updated model name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Updated model details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "model", + "success" + ] + }, + "ModelsUpdateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "New name for the model", + "example": "My Renamed Model" + } + }, + "required": [ + "name" + ] + }, + "JobsGetStatusResponse": { + "type": "object", + "properties": { + "job_id": { + "type": "string", + "description": "The job ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "job_type": { + "type": "string", + "description": "The type of job (e.g., REFRESH_SCHEMA)", + "example": "REFRESH_SCHEMA" + }, + "status": { + "type": "string", + "enum": [ + "IN_PROGRESS", + "COMPLETED", + "FAILED" + ], + "description": "Current status of the job", + "example": "COMPLETED" + } + }, + "required": [ + "job_id", + "job_type", + "status" + ] + }, + "ModelsGetSchemasResponse": { + "type": "object", + "properties": { + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" + } + }, + "required": [ + "schemas" + ] + }, + "ModelsGetViewResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "View description" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Field name" + }, + "type": { + "type": "string", + "enum": [ + "dimension", + "measure", + "filter" + ], + "description": "Field type" + } + }, + "required": [ + "name", + "type" + ] + }, + "description": "Fields in the view" + }, + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { + "type": "string", + "description": "View label" + }, + "name": { + "type": "string", + "description": "View name" + } + }, + "required": [ + "fields", + "name" + ] + }, + "description": "List of views" + } + }, + "required": [ + "success", + "views" + ] + }, + "ModelsUpdateViewBody": { + "type": "object", + "properties": { + "aiContext": { + "type": "string", + "description": "AI context for the view" + }, + "description": { + "type": "string", + "description": "View description" + }, + "format": { + "type": "string", + "description": "View format" + }, + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { + "type": "string", + "description": "View label" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the view" + } + } + }, + "ModelsUpdateFieldBody": { + "type": "object", + "properties": { + "aiContext": { + "type": "string", + "description": "AI context for the field" + }, + "allValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Deprecated: use sampleValues instead" + }, + "binBoundaries": { + "type": "array", + "items": { + "type": "number" + }, + "description": "Bin boundaries for binned fields" + }, + "binLabels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels for bins" + }, + "description": { + "type": "string", + "description": "Field description" + }, + "drillFields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Drill-down fields" + }, + "elseValue": { + "type": "string", + "description": "Else value for grouped fields" + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filters for the field" + }, + "format": { + "type": "string", + "description": "Field format" + }, + "groupFilters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Group filters" + }, + "groupLabel": { + "type": "string", + "description": "Group label" + }, + "groupNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Group names" + }, + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" + }, + "ignored": { + "type": "boolean", + "description": "Whether the field is ignored" + }, + "isCalc": { + "type": "boolean", + "description": "Whether this is a calculation field" + }, + "label": { + "type": "string", + "description": "Field label" + }, + "newFieldName": { + "type": "string", + "description": "New field name (for rename)" + }, + "newViewName": { + "type": "string", + "description": "New view name (for move)" + }, + "sampleValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sample values for the field" + }, + "sql": { + "type": "string", + "description": "SQL expression for the field" + }, + "synonyms": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Synonyms for the field" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for the field" + } + } + }, + "ModelsListTopicsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topics": { + "type": "array", + "items": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + } + }, + "required": [ + "base_view_name", + "name" + ] + }, + "description": "List of topics" + } + }, + "required": [ + "success", + "topics" + ] + }, + "ModelsGetTopicResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topic": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + }, + "relationships": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Relationships for the topic" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Views available in the topic" + } + }, + "required": [ + "base_view_name", + "name", + "relationships", + "views" + ], + "description": "Topic details with relationships and views" + } + }, + "required": [ + "success", + "topic" + ] + }, + "ModelsUpdateTopicBody": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Topic description" + }, + "groupLabel": { + "type": "string", + "description": "Group label for the topic" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "newTopicName": { + "type": "string", + "description": "New topic name (for rename)" + } + } + }, + "ModelsCreateFieldBody": { + "type": "object", + "properties": { + "aggregateType": { + "type": "string", + "enum": [ + "AVERAGE", + "COUNT", + "COUNT_DISTINCT", + "LIST", + "MAX", + "MIN", + "SUM", + "MEDIAN", + "PERCENTILE", + "AVERAGE_DISTINCT_ON", + "SUM_DISTINCT_ON", + "MEDIAN_DISTINCT_ON", + "PERCENTILE_DISTINCT_ON", + "SEMANTIC_VIEW_AGG" + ], + "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", + "example": "SUM" + }, + "aiContext": { + "type": "string", + "description": "AI context for the field" + }, + "description": { + "type": "string", + "description": "Field description" + }, + "fieldName": { + "type": "string", + "description": "Field name", + "example": "total_revenue" + }, + "format": { + "type": "string", + "description": "Field format" + }, + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" + }, + "label": { + "type": "string", + "description": "Field label" + }, + "sql": { + "type": "string", + "description": "SQL expression for the field" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for topic-scoped fields" + }, + "viewName": { + "type": "string", + "description": "View to add the field to", + "example": "orders" + } + }, + "required": [ + "fieldName", + "viewName" + ], + "additionalProperties": false + }, + "ModelsRefreshResponse": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "description": "Job ID for the refresh operation" + }, + "modelId": { + "type": "string", + "description": "Model ID being refreshed" + }, + "status": { + "type": "string", + "enum": [ + "running", + "completed", + "failed" + ], + "description": "Current status of the refresh" + } + }, + "required": [ + "jobId", + "modelId", + "status" + ] + }, + "ModelsValidateResponse": { + "type": "object", + "properties": { + "issues": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field name with the issue" + }, + "message": { + "type": "string", + "description": "Validation issue message" + }, + "severity": { + "type": "string", + "enum": [ + "error", + "warning" + ], + "description": "Issue severity" + }, + "view": { + "type": "string", + "description": "View name with the issue" + } + }, + "required": [ + "message", + "severity" + ] + }, + "description": "List of validation issues" + }, + "valid": { + "type": "boolean", + "description": "Whether the model is valid" + } + }, + "required": [ + "issues", + "valid" + ] + }, + "ModelsMigrateBody": { + "type": "object", + "properties": { + "branchName": { + "type": "string", + "description": "Branch name for the target model" + }, + "commitMessage": { + "type": "string", + "description": "Commit message for git sync" + }, + "deleteViewsAndTopicsMissingFromSource": { + "type": "boolean", + "default": true, + "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead — useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." + }, + "gitRef": { + "type": "string", + "description": "Git reference" + }, + "targetModelId": { + "type": "string", + "format": "uuid", + "description": "Target model ID to migrate to" + } + }, + "required": [ + "targetModelId" + ] + }, + "ModelsDbtExposuresResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtExposureWithMeta" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "DbtExposureWithMeta": { + "type": "object", + "properties": { + "dashboard_identifier": { + "type": "string", + "description": "Identifier of the dashboard that generated this exposure" + }, + "deduplication_name": { + "type": "string", + "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." + }, + "exposure": { + "$ref": "#/components/schemas/DbtExposure" + } + }, + "required": [ + "dashboard_identifier", + "deduplication_name", + "exposure" + ] + }, + "DbtExposure": { + "type": "object", + "properties": { + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of dbt model references (e.g. ref('model_name'))", + "example": [ + "ref('orders')", + "ref('customers')" + ] + }, + "label": { + "type": "string", + "description": "Original dashboard name" + }, + "name": { + "type": "string", + "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", + "example": "my_dashboard" + }, + "owner": { + "$ref": "#/components/schemas/DbtExposureOwner" + }, + "type": { + "type": "string", + "enum": [ + "dashboard", + "notebook", + "analysis", + "ml", + "application" + ], + "description": "Type of the exposure", + "example": "dashboard" + }, + "url": { + "type": "string", + "description": "URL of the dashboard" + } + }, + "required": [ + "depends_on", + "name", + "owner", + "type" + ], + "description": "The dbt exposure for this dashboard." + }, + "DbtExposureOwner": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email of the dashboard owner" + }, + "name": { + "type": "string", + "description": "Name of the dashboard owner" + } + }, + "required": [ + "email", + "name" + ] + }, + "ModelsBranchDbtBody": { + "type": "object", + "properties": { + "dbt_environment_id": { + "type": "string", + "format": "uuid", + "description": "ID of the dbt environment to activate on this branch", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "dbt_git_branch": { + "type": "string", + "description": "Git branch to associate with the dbt environment", + "example": "feature/new-metrics" + } + }, + "required": [ + "dbt_environment_id" + ] + }, + "ModelsMergeBranchResponse": { + "type": "object", + "properties": { + "failed_drafts_count": { + "type": "number", + "description": "Number of drafts that failed to publish" + }, + "git_synced": { + "type": "boolean", + "description": "Whether git was synced" + }, + "published_drafts_count": { + "type": "number", + "description": "Number of drafts published" + }, + "success": { + "type": "boolean", + "description": "Whether the merge succeeded" + } + }, + "required": [ + "failed_drafts_count", + "git_synced", + "published_drafts_count", + "success" + ] + }, + "ModelsMergeBranchBody": { + "type": "object", + "properties": { + "commit_message": { + "type": "string", + "description": "Custom commit message for git sync" + }, + "delete_branch": { + "type": "boolean", + "default": false, + "description": "Delete the branch after merging" + }, + "force_override_git_settings": { + "type": "boolean", + "default": false, + "description": "Override PR-required or git-follower settings" + }, + "publish_drafts": { + "type": "boolean", + "default": true, + "description": "Publish branch-attached drafts" + } + } + }, + "ModelsCommitResponse": { + "type": "object", + "properties": { + "did_sync": { + "type": "boolean", + "description": "Whether a sync operation was performed against git" + }, + "git_sha": { + "type": [ + "string", + "null" + ], + "description": "The git SHA of the commit that was pushed (null if no commit was needed)" + }, + "in_sync": { + "type": "boolean", + "description": "Whether the branch is in sync with git after the operation" + }, + "pr_url": { + "type": [ + "string", + "null" + ], + "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." + } + }, + "required": [ + "did_sync", + "git_sha", + "in_sync", + "pr_url" + ] + }, + "ModelsCommitBody": { + "type": "object", + "properties": { + "allow_branch_exists": { + "type": "boolean", + "default": true, + "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", + "example": true + }, + "branch_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to commit.", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "commit_message": { + "type": "string", + "minLength": 1, + "description": "Commit message for the git commit.", + "example": "Add new orders view" + }, + "require_branch_exists": { + "type": "boolean", + "default": false, + "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", + "example": false + } + }, + "required": [ + "branch_id", + "commit_message" + ] + }, + "ModelsCacheResetResponse": { + "type": "object", + "properties": { + "cache_reset": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "Creation timestamp" + }, + "model_id": { + "type": "string", + "description": "Model ID" + }, + "policy_name": { + "type": "string", + "description": "Cache policy name" + }, + "reset_at": { + "type": [ + "string", + "null" + ], + "description": "Reset timestamp" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "Last update timestamp" + } + }, + "required": [ + "created_at", + "model_id", + "policy_name", + "reset_at", + "updated_at" + ], + "description": "Cache reset details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "cache_reset", + "success" + ] + }, + "ModelsCacheResetBody": { + "type": "object", + "properties": { + "resetAt": { + "type": "string", + "description": "ISO-8601 timestamp for when to reset the cache", + "example": "2024-01-15T12:00:00Z" + } + } + }, + "ModelsGitGetResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { "type": "string", "description": "Clone URL of the git repository (SSH or HTTPS)", "example": "git@github.com:org/repo.git" @@ -5482,6 +27259,11 @@ "type": "string", "description": "Optional branch ID" }, + "creator_id": { + "type": "string", + "format": "uuid", + "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." + }, "find": { "type": "string", "minLength": 1, @@ -5580,7 +27362,7 @@ "extension", "staged", "merged", - "history" + "fully-resolved" ], "default": "combined", "description": "IDE mode for YAML operations" @@ -5613,6 +27395,50 @@ ], "additionalProperties": false }, + "AiAgentActionsResponse": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiAgentAction" + }, + "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." + } + }, + "required": [ + "records" + ] + }, + "AiAgentAction": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "sample", + "skill" + ], + "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", + "example": "skill" + }, + "label": { + "type": "string", + "description": "Short, human-readable name for the action — chip text in client UIs and the visible \"prompt\" on the answer card.", + "example": "Revenue trends" + }, + "prompt": { + "type": "string", + "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", + "example": "Skill:\nShow me the recent revenue trends grouped by month…" + } + }, + "required": [ + "kind", + "label", + "prompt" + ] + }, "QueryRunResponse": { "type": "object", "properties": { @@ -5710,7 +27536,7 @@ "userId": { "type": "string", "format": "uuid", - "description": "User ID to execute the query as (for row-level security). Only valid for org-scoped API keys.", + "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter — this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", "example": "550e8400-e29b-41d4-a716-446655440000" } } @@ -5926,7 +27752,7 @@ "example": false }, "filterConfig": { - "description": "Applied dashboard filter configuration" + "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." }, "id": { "type": "string", @@ -6632,6 +28458,76 @@ { "type": "object", "properties": { + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, "active": { "type": "boolean" }, @@ -7223,232 +29119,612 @@ } }, "required": [ - "records" + "records" + ] + }, + "UploadsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Upload" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Upload": { + "type": "object", + "properties": { + "connection_id": { + "type": "string", + "format": "uuid", + "description": "Connection ID the upload is associated with" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "When the file was uploaded" + }, + "file_name": { + "type": "string", + "description": "Original file name", + "example": "users.csv" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" + }, + "in_db_as_table_name": { + "type": [ + "string", + "null" + ], + "description": "Database table name if uploaded to database scratch schema" + }, + "model_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" + }, + "size_bytes": { + "type": [ + "number", + "null" + ], + "description": "File size in bytes" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" + }, + "uploaded_by_user": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "User ID of the uploader" + }, + "name": { + "type": "string", + "description": "Name of the user who uploaded the file" + } + }, + "required": [ + "id", + "name" + ], + "description": "User who uploaded the file" + }, + "view_name": { + "type": "string", + "description": "View name associated with the upload" + } + }, + "required": [ + "connection_id", + "created_at", + "file_name", + "id", + "in_db_as_table_name", + "model_id", + "size_bytes", + "updated_at", + "uploaded_by_user", + "view_name" + ] + }, + "UploadCreateResponse": { + "type": "object", + "properties": { + "fileName": { + "type": "string", + "description": "Original file name", + "example": "users.csv" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" + }, + "inDbAsTableName": { + "type": "string", + "description": "Database table name in the scratch schema" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID the view was created in" + }, + "rowCount": { + "type": "integer", + "description": "Number of rows in the uploaded file" + }, + "truncated": { + "type": "boolean", + "description": "Whether the file was truncated due to row limit" + }, + "viewCreated": { + "type": "boolean", + "description": "Whether a view was created in the model" + }, + "viewName": { + "type": "string", + "description": "Name of the view created" + } + }, + "required": [ + "fileName", + "id", + "inDbAsTableName", + "modelId", + "rowCount", + "truncated", + "viewCreated", + "viewName" + ] + }, + "UploadCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" + }, + "branchName": { + "type": "string", + "description": "Name of the branch to create the view in (mutually exclusive with branchId)" + }, + "file": { + "type": "string", + "description": "The CSV file to upload", + "format": "binary" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "UUID of the model to create the view in" + }, + "viewName": { + "type": "string", + "description": "Override the view name (defaults to sanitized file name)" + } + }, + "required": [ + "file", + "modelId" + ] + }, + "UploadDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the deletion was successful" + } + }, + "required": [ + "success" ] }, - "UploadsListResponse": { + "UsersGetModelRolesResponse": { "type": "object", "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" }, - "records": { + "results": { "type": "array", "items": { - "$ref": "#/components/schemas/Upload" - } + "$ref": "#/components/schemas/RoleAssignmentResult" + }, + "description": "List of role assignments" } }, "required": [ - "pageInfo", - "records" + "membershipId", + "results" ] }, - "Upload": { + "RoleAssignmentResult": { "type": "object", "properties": { - "connection_id": { + "baseRole": { "type": "string", - "format": "uuid", - "description": "Connection ID the upload is associated with" + "description": "The base role definition name", + "example": "VIEWER" }, - "created_at": { + "connectionId": { "type": "string", - "format": "date-time", - "description": "When the file was uploaded" + "format": "uuid", + "description": "Connection this role applies to" }, - "file_name": { - "type": "string", - "description": "Original file name", - "example": "users.csv" + "from": { + "$ref": "#/components/schemas/RoleOrigin" }, - "id": { + "modelId": { "type": "string", "format": "uuid", - "description": "Unique identifier for the upload" - }, - "in_db_as_table_name": { - "type": [ - "string", - "null" - ], - "description": "Database table name if uploaded to database scratch schema" + "description": "Model this role applies to" }, - "model_id": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" }, - "size_bytes": { - "type": [ - "number", - "null" - ], - "description": "File size in bytes" + "resolved": { + "type": "boolean", + "description": "Whether this is the resolved (effective) role" }, - "updated_at": { + "roleName": { "type": "string", - "format": "date-time", - "description": "Last update timestamp" + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "resolved", + "roleName" + ] + }, + "RoleOrigin": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "USER" + ], + "description": "Role assigned directly to user" + } + }, + "required": [ + "type" + ] }, - "uploaded_by_user": { - "type": [ - "object", - "null" - ], + { + "type": "object", "properties": { - "id": { + "type": { "type": "string", - "format": "uuid", - "description": "User ID of the uploader" + "enum": [ + "ORG" + ], + "description": "Role inherited from organization" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "BASE" + ], + "description": "Connection base role" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" }, "name": { "type": "string", - "description": "Name of the user who uploaded the file" + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role inherited from group membership" } }, "required": [ - "id", - "name" - ], - "description": "User who uploaded the file" + "depth", + "miniUuid", + "name", + "type" + ] + } + ], + "description": "Origin of this role assignment" + }, + "UsersAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" }, - "view_name": { + "membershipId": { "type": "string", - "description": "View name associated with the upload" + "format": "uuid", + "description": "The user membership ID" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" + }, + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + } + }, + "required": [ + "connectionId", + "membershipId", + "modelId", + "roleName" + ] + }, + "UsersAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" + } + }, + "required": [ + "roleName" + ] + }, + "UsersListEmailOnlyResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "User email address", + "example": "user@example.com" + }, + "user_attributes": { + "type": "object", + "additionalProperties": {}, + "description": "User attributes as key-value pairs" + }, + "user_id": { + "type": "string", + "format": "uuid", + "description": "User ID" + } + }, + "required": [ + "email", + "user_attributes", + "user_id" + ] + } } }, "required": [ - "connection_id", - "created_at", - "file_name", - "id", - "in_db_as_table_name", - "model_id", - "size_bytes", - "updated_at", - "uploaded_by_user", - "view_name" + "pageInfo", + "records" ] }, - "UploadCreateResponse": { + "UsersCreateEmailOnlyResponse": { "type": "object", "properties": { - "fileName": { - "type": "string", - "description": "Original file name", - "example": "users.csv" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the upload" - }, - "inDbAsTableName": { + "email": { "type": "string", - "description": "Database table name in the scratch schema" + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" }, - "modelId": { + "userId": { "type": "string", "format": "uuid", - "description": "Model ID the view was created in" - }, - "rowCount": { - "type": "integer", - "description": "Number of rows in the uploaded file" - }, - "truncated": { - "type": "boolean", - "description": "Whether the file was truncated due to row limit" - }, - "viewCreated": { - "type": "boolean", - "description": "Whether a view was created in the model" - }, - "viewName": { - "type": "string", - "description": "Name of the view created" + "description": "ID of the created user" } }, "required": [ - "fileName", - "id", - "inDbAsTableName", - "modelId", - "rowCount", - "truncated", - "viewCreated", - "viewName" + "email", + "userId" ] }, - "UploadCreateBody": { + "UsersCreateEmailOnlyBody": { "type": "object", "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" - }, - "branchName": { - "type": "string", - "description": "Name of the branch to create the view in (mutually exclusive with branchId)" - }, - "file": { - "type": "string", - "description": "The CSV file to upload", - "format": "binary" - }, - "modelId": { + "email": { "type": "string", - "format": "uuid", - "description": "UUID of the model to create the view in" + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" }, - "viewName": { - "type": "string", - "description": "Override the view name (defaults to sanitized file name)" + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" } }, "required": [ - "modelId" + "email" ] }, - "UploadDeleteResponse": { + "UsersCreateEmailOnlyBulkResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the deletion was successful" + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "description": "Results for each created user" } }, "required": [ - "success" + "results" ] }, - "UsersGetModelRolesResponse": { + "UsersCreateEmailOnlyBulkBody": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "minItems": 1, + "maxItems": 20, + "description": "Array of users to create (1-20 users)" + } + }, + "required": [ + "users" + ] + }, + "UserGroupsGetModelRolesResponse": { "type": "object", "properties": { - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" - }, "results": { "type": "array", "items": { - "$ref": "#/components/schemas/RoleAssignmentResult" + "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" }, "description": "List of role assignments" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" } }, "required": [ - "membershipId", - "results" + "results", + "userGroupId" ] }, - "RoleAssignmentResult": { + "UserGroupRoleAssignmentResult": { "type": "object", "properties": { "baseRole": { @@ -7462,7 +29738,7 @@ "description": "Connection this role applies to" }, "from": { - "$ref": "#/components/schemas/RoleOrigin" + "$ref": "#/components/schemas/UserGroupRoleOrigin" }, "modelId": { "type": "string", @@ -7473,109 +29749,55 @@ "type": "number", "description": "Priority for role resolution (higher = more permissive)" }, - "resolved": { - "type": "boolean", - "description": "Whether this is the resolved (effective) role" - }, "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" - } - }, - "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "resolved", - "roleName" - ] - }, - "RoleOrigin": { - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "USER" - ], - "description": "Role assigned directly to user" - } - }, - "required": [ - "type" - ] + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "roleName" + ] + }, + "UserGroupRoleOrigin": { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group (0 for direct assignment)" }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "ORG" - ], - "description": "Role inherited from organization" - } - }, - "required": [ - "type" - ] + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "BASE" - ], - "description": "Connection base role" - } - }, - "required": [ - "type" - ] + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" }, - { - "type": "object", - "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { - "type": "string", - "description": "Name of the group", - "example": "Engineering Team" - }, - "type": { - "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role inherited from group membership" - } - }, - "required": [ - "depth", - "miniUuid", - "name", - "type" - ] + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role assigned to group" } + }, + "required": [ + "depth", + "miniUuid", + "name", + "type" ], "description": "Origin of this role assignment" }, - "UsersAssignModelRoleResponse": { + "UserGroupsAssignModelRoleResponse": { "type": "object", "properties": { "connectionId": { @@ -7583,11 +29805,6 @@ "format": "uuid", "description": "The connection ID for this role assignment" }, - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" - }, "modelId": { "type": "string", "format": "uuid", @@ -7597,16 +29814,21 @@ "type": "string", "description": "The assigned role name", "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" } }, "required": [ "connectionId", - "membershipId", "modelId", - "roleName" + "roleName", + "userGroupId" ] }, - "UsersAssignModelRoleBody": { + "UserGroupsAssignModelRoleBody": { "type": "object", "properties": { "connectionId": { @@ -7631,367 +29853,432 @@ "required": [ "roleName" ] - }, - "UsersListEmailOnlyResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + } + }, + "parameters": {} + }, + "paths": { + "/api/v1/ai/generate-query": { + "post": { + "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", + "operationId": "aiGenerateQuery", + "summary": "Generate query from natural language", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "402": { + "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditShutoffError" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model or topic was not found in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/pick-topic": { + "post": { + "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", + "operationId": "aiPickTopic", + "summary": "Pick the best topic for a prompt", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicBody" + } + } + } + }, + "responses": { + "200": { + "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. The prompt or modelId may be missing or malformed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "description": "User email address", - "example": "user@example.com" - }, - "user_attributes": { - "type": "object", - "additionalProperties": {}, - "description": "User attributes as key-value pairs" - }, - "user_id": { - "type": "string", - "format": "uuid", - "description": "User ID" + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" } - }, - "required": [ - "email", - "user_attributes", - "user_id" - ] + } } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "UsersCreateEmailOnlyResponse": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" }, - "userId": { - "type": "string", - "format": "uuid", - "description": "ID of the created user" + "404": { + "description": "The specified model was not found, or no accessible topics exist in the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/search-omni-docs": { + "post": { + "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", + "operationId": "aiSearchOmniDocs", + "summary": "Search Omni documentation", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsBody" + } + } } }, - "required": [ - "email", - "userId" - ] - }, - "UsersCreateEmailOnlyBody": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" + "responses": { + "200": { + "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsResponse" + } + } + } }, - "userAttributes": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" + "400": { + "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" } - ] - }, - "description": "Optional user attributes as key-value pairs" - } - }, - "required": [ - "email" - ] - }, - "UsersCreateEmailOnlyBulkResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "ID of the created user" + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" } - }, - "required": [ - "email", - "userId" - ] - }, - "description": "Results for each created user" - } - }, - "required": [ - "results" - ] - }, - "UsersCreateEmailOnlyBulkBody": { - "type": "object", - "properties": { - "users": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" - }, - "userAttributes": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "Optional user attributes as key-value pairs" + } + } + }, + "403": { + "description": "Omni Agent is not enabled for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" } - }, - "required": [ - "email" - ] - }, - "minItems": 1, - "maxItems": 20, - "description": "Array of users to create (1-20 users)" + } + } + }, + "500": { + "description": "AI service error." } - }, - "required": [ - "users" - ] - }, - "UserGroupsGetModelRolesResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" + } + } + }, + "/api/v1/ai/jobs": { + "post": { + "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", + "operationId": "aiJobSubmit", + "summary": "Submit an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" }, - "description": "List of role assignments" - }, - "userGroupId": { - "type": "string", - "description": "The user group short identifier", - "example": "abc123" + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitBody" + } + } } }, - "required": [ - "results", - "userGroupId" - ] - }, - "UserGroupRoleAssignmentResult": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "The base role definition name", - "example": "VIEWER" + "responses": { + "201": { + "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitResponse" + } + } + } }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection this role applies to" + "400": { + "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } }, - "from": { - "$ref": "#/components/schemas/UserGroupRoleOrigin" + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model this role applies to" + "403": { + "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } }, - "priority": { - "type": "number", - "description": "Priority for role resolution (higher = more permissive)" + "404": { + "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } }, - "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" + "409": { + "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } } - }, - "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "roleName" - ] - }, - "UserGroupRoleOrigin": { - "type": "object", - "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group (0 for direct assignment)" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { - "type": "string", - "description": "Name of the group", - "example": "Engineering Team" - }, - "type": { - "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role assigned to group" + } + } + }, + "/api/v1/ai/jobs/{jobId}": { + "get": { + "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", + "operationId": "aiJobStatus", + "summary": "Get AI job status", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" } - }, - "required": [ - "depth", - "miniUuid", - "name", - "type" ], - "description": "Origin of this role assignment" - }, - "UserGroupsAssignModelRoleResponse": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "The connection ID for this role assignment" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The model ID for this role assignment" - }, - "roleName": { - "type": "string", - "description": "The assigned role name", - "example": "VIEWER" + "responses": { + "200": { + "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobStatusResponse" + } + } + } }, - "userGroupId": { - "type": "string", - "description": "The user group short identifier", - "example": "abc123" - } - }, - "required": [ - "connectionId", - "modelId", - "roleName", - "userGroupId" - ] - }, - "UserGroupsAssignModelRoleBody": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model ID for model-level role assignment. Required if connectionId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } }, - "roleName": { - "type": "string", - "minLength": 1, - "description": "Name of the role to assign (base or custom role)", - "example": "VIEWER" + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } } - }, - "required": [ - "roleName" - ] + } } }, - "parameters": {} - }, - "paths": { - "/api/v1/ai/generate-query": { + "/api/v1/ai/jobs/{jobId}/cancel": { "post": { - "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", - "operationId": "aiGenerateQuery", - "summary": "Generate query from natural language", + "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", + "operationId": "aiJobCancel", + "summary": "Cancel an AI job", "tags": [ "AI" ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiGenerateQueryBody" - } - } + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" } - }, + ], "responses": { "200": { - "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed.", + "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiGenerateQueryResponse" + "$ref": "#/components/schemas/AiJobCancelResponse" } } } }, "400": { - "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", + "description": "Invalid job ID format. Must be a valid UUID.", "content": { "application/json": { "schema": { @@ -8011,7 +30298,7 @@ } }, "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", + "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", "content": { "application/json": { "schema": { @@ -8021,7 +30308,7 @@ } }, "404": { - "description": "The specified model or topic was not found in the organization.", + "description": "Job not found. The job may not exist or may belong to a different organization.", "content": { "application/json": { "schema": { @@ -8030,43 +30317,54 @@ } } }, - "500": { - "description": "AI service error." + "409": { + "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } } } } }, - "/api/v1/ai/pick-topic": { - "post": { - "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", - "operationId": "aiPickTopic", - "summary": "Pick the best topic for a prompt", + "/api/v1/ai/jobs/{jobId}/result": { + "get": { + "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", + "operationId": "aiJobResult", + "summary": "Get AI job result", "tags": [ "AI" ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiPickTopicBody" - } - } + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" } - }, + ], "responses": { "200": { - "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", + "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiPickTopicResponse" + "$ref": "#/components/schemas/AiJobResultResponse" } } } }, "400": { - "description": "Invalid request body. The prompt or modelId may be missing or malformed.", + "description": "Invalid job ID format. Must be a valid UUID.", "content": { "application/json": { "schema": { @@ -8085,18 +30383,75 @@ } } }, - "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", + "404": { + "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError403" + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/vis": { + "get": { + "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", + "operationId": "aiJobVisualization", + "summary": "Render AI job visualization", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "content": { + "image/png": { + "schema": { + "format": "binary", + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" } } } }, "404": { - "description": "The specified model was not found, or no accessible topics exist in the model.", + "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", "content": { "application/json": { "schema": { @@ -8105,47 +30460,114 @@ } } }, - "500": { - "description": "AI service error." + "422": { + "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError422" + } + } + } } } } }, - "/api/v1/ai/search-omni-docs": { - "post": { - "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", - "operationId": "aiSearchOmniDocs", - "summary": "Search Omni documentation", + "/api/v1/ai/branding": { + "get": { + "description": "Returns the organization's AI helper branding — display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", + "operationId": "aiBranding", + "summary": "Get AI helper branding", "tags": [ "AI" ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsBody" - } - } - } - }, "responses": { "200": { - "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", + "description": "AI branding retrieved successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsResponse" + "$ref": "#/components/schemas/AiBrandingResponse" } } } }, - "400": { - "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations": { + "get": { + "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next page.", + "operationId": "aiConversationsList", + "summary": "List AI conversations", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of conversations.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError400" + "$ref": "#/components/schemas/AiConversationsListResponse" } } } @@ -8161,7 +30583,7 @@ } }, "403": { - "description": "Omni Agent is not enabled for this organization.", + "description": "Insufficient permissions.", "content": { "application/json": { "schema": { @@ -8169,18 +30591,15 @@ } } } - }, - "500": { - "description": "AI service error." } } } }, - "/api/v1/ai/jobs": { - "post": { - "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", - "operationId": "aiJobSubmit", - "summary": "Submit an AI job", + "/api/v1/ai/conversations/{conversationId}": { + "get": { + "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", + "operationId": "aiConversationDetail", + "summary": "Get AI conversation with messages", "tags": [ "AI" ], @@ -8188,41 +30607,20 @@ { "schema": { "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" + "format": "uuid" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "name": "conversationId", + "in": "path" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitBody" - } - } - } - }, "responses": { - "201": { - "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitResponse" - } - } - } - }, - "400": { - "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", + "200": { + "description": "Conversation with messages in chronological order.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError400" + "$ref": "#/components/schemas/AiConversationDetailResponse" } } } @@ -8238,7 +30636,7 @@ } }, "403": { - "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", + "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", "content": { "application/json": { "schema": { @@ -8248,7 +30646,7 @@ } }, "404": { - "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", + "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user — existence of another user's conversations is not disclosed.", "content": { "application/json": { "schema": { @@ -8256,572 +30654,1529 @@ } } } + } + } + } + }, + "/api/v1/api-keys": { + "get": { + "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", + "operationId": "apiKeysList", + "summary": "List API tokens", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Cursor from the previous response (token UUID)" + }, + "required": false, + "description": "Cursor from the previous response (token UUID)", + "name": "cursor", + "in": "query" }, - "409": { - "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "createdAt", + "name" + ], + "default": "createdAt" + }, + "required": false, + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Filter by API token type. When omitted, all types are returned.", + "example": "personal" + }, + "required": false, + "description": "Filter by API token type. When omitted, all types are returned.", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of API tokens", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError409" + "$ref": "#/components/schemas/ApiKeyListResponse" } } } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" } } } }, - "/api/v1/ai/jobs/{jobId}": { + "/api/v1/api-keys/{id}": { "get": { - "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", - "operationId": "aiJobStatus", - "summary": "Get AI job status", + "description": "Returns a single API token by id. Requires organization admin permissions.", + "operationId": "apiKeysGet", + "summary": "Get API token", "tags": [ - "AI" + "API Tokens" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }, "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", + "description": "Token UUID", + "name": "id", "in": "path" } ], "responses": { "200": { - "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", + "description": "The requested API token", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiJobStatusResponse" + "$ref": "#/components/schemas/ApiKey" } } } }, "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "description": "Malformed `id` (must be a UUID)" }, "401": { - "description": "Missing or invalid API key.", + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Token not found in this organization" + } + } + }, + "put": { + "description": "Enables or disables an API token. Requires organization admin permissions.", + "operationId": "apiKeysUpdate", + "summary": "Enable or disable an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "The updated API token", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError401" + "$ref": "#/components/schemas/ApiKey" } } } }, + "400": { + "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + }, + "delete": { + "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", + "operationId": "apiKeysDelete", + "summary": "Revoke an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The token was revoked", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError404" + "$ref": "#/components/schemas/ApiKeyDeleteResponse" } } } + }, + "400": { + "description": "Malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" } } } }, - "/api/v1/ai/jobs/{jobId}/cancel": { - "post": { - "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", - "operationId": "aiJobCancel", - "summary": "Cancel an AI job", + "/api/v1/connections": { + "get": { + "operationId": "connectionsList", + "summary": "List connections", "tags": [ - "AI" + "Connections" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Filter by database name (case-insensitive contains)", + "example": "analytics" }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" + "required": false, + "description": "Filter by database name (case-insensitive contains)", + "name": "database", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "example": "snowflake,bigquery" + }, + "required": false, + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "name": "dialect", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "description": "Include soft-deleted connections in results", + "example": false + }, + "required": false, + "description": "Include soft-deleted connections in results", + "name": "includeDeleted", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by connection name (case-insensitive contains)", + "example": "Production" + }, + "required": false, + "description": "Filter by connection name (case-insensitive contains)", + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "desc" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "database", + "dialect", + "name" + ], + "description": "Field to sort by", + "example": "name" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" } ], "responses": { "200": { - "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", + "description": "List of connections", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiJobCancelResponse" + "type": "object", + "properties": { + "connections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "description": "Whether branch environments override user attributes", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + }, + "description": "List of connections" + } + }, + "required": [ + "connections" + ], + "description": "List connections response", + "title": "ConnectionsListResponse" } } } - }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + }, + "post": { + "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", + "operationId": "connectionsCreate", + "summary": "Create connection", + "tags": [ + "Connections" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "acceptsLicense": { + "type": "boolean", + "description": "Acceptance of the license terms. Required for Oracle connections.", + "example": true + }, + "allowsUserSpecificTimezones": { + "type": "boolean", + "default": false, + "description": "Whether to allow users to specify their own timezones", + "example": false + }, + "alwaysScopeViewNames": { + "type": "boolean", + "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", + "example": true + }, + "authenticationType": { + "type": "string", + "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", + "example": "snowflake-password" + }, + "awsRoleArn": { + "type": "string", + "description": "AWS IAM role ARN. Applicable for Athena only.", + "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" + }, + "baseRole": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "RESTRICTED_QUERIER", + "QUERIER", + "MODELER", + "CONNECTION_ADMIN" + ], + "description": "The default role for users accessing the connection", + "example": "QUERIER" + }, + "database": { + "type": "string", + "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", + "example": "analytics_db" + }, + "defaultSchema": { + "type": "string", + "description": "The default schema to use. Required for MSSQL.", + "example": "public" + }, + "dialect": { + "type": "string", + "enum": [ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "exasol", + "mariadb", + "motherduck", + "mssql", + "mysql", + "oracle", + "postgres", + "redshift", + "sap_hana", + "snowflake", + "starrocks", + "trino" + ], + "description": "The database dialect", + "example": "snowflake" + }, + "enableDbSemanticLayerIntegration": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", + "example": false + }, + "enableDbSemanticLayerTopics": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", + "example": false + }, + "externalOauthAudience": { + "type": "string", + "description": "External OAuth audience claim. Applicable for Snowflake." + }, + "externalOauthAuthorizationUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/authorize" + }, + "externalOauthTokenUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/token" + }, + "host": { + "type": "string", + "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", + "example": "myaccount" + }, + "hostOverride": { + "type": "string", + "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", + "example": "myaccount.snowflakecomputing.com" + }, + "includeOtherCatalogs": { + "type": "string", + "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", + "example": "other_project1,other_project2" + }, + "includeSchemas": { + "type": "string", + "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", + "example": "public,analytics" + }, + "inferRelationshipsFromColumnNames": { + "type": "boolean", + "default": true, + "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", + "example": true + }, + "inferRelationshipsFromForeignKeys": { + "type": "boolean", + "default": false, + "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "example": false + }, + "maxBillingBytes": { + "type": "string", + "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", + "example": "1000000000" + }, + "name": { + "type": "string", + "description": "A descriptive name for the connection", + "example": "Production Warehouse" + }, + "oauthClientId": { + "type": "string", + "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "oauthClientSecretUnencrypted": { + "type": "string", + "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "offloadedSchemas": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", + "example": [ + "analytics_archive" + ] + }, + "passwordUnencrypted": { + "type": "string", + "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." + }, + "port": { + "type": "integer", + "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", + "example": 5432 + }, + "privateKey": { + "type": "string", + "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." + }, + "queryTimeoutSeconds": { + "type": "integer", + "maximum": 3600, + "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", + "example": 900 + }, + "queryTimezone": { + "type": "string", + "description": "The timezone to use for queries", + "example": "NONE" + }, + "region": { + "type": "string", + "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", + "example": "us-east-1" + }, + "scratchSchema": { + "type": "string", + "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", + "example": "omni_scratch" + }, + "systemTimezone": { + "type": "string", + "description": "The timezone to use for the system", + "example": "UTC" + }, + "trustServerCertificate": { + "type": "boolean", + "default": false, + "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", + "example": false + }, + "useMachineAuth": { + "type": "boolean", + "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "example": false + }, + "username": { + "type": "string", + "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", + "example": "analytics_user" + }, + "warehouse": { + "type": "string", + "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path).", + "example": "COMPUTE_WH" + } + }, + "required": [ + "dialect", + "name", + "passwordUnencrypted" + ], + "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", + "title": "ConnectionsCreateBody" } } - }, - "401": { - "description": "Missing or invalid API key.", + } + }, + "responses": { + "201": { + "description": "Connection created successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError401" + "type": "object", + "properties": { + "data": { + "type": "string", + "format": "uuid", + "description": "Created connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "data", + "success" + ], + "description": "Create connection response", + "title": "ConnectionsCreateResponse" } } } }, - "403": { - "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "400": { + "description": "Invalid request body or dialect" }, - "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "401": { + "description": "Authentication required" }, - "409": { - "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } + "403": { + "description": "Permission denied - admin role required" } } } }, - "/api/v1/ai/jobs/{jobId}/result": { + "/api/v1/connections/{id}": { "get": { - "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", - "operationId": "aiJobResult", - "summary": "Get AI job result", + "description": "Fetch a single connection by ID.", + "operationId": "connectionsGet", + "summary": "Get connection", "tags": [ - "AI" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", + "description": "Connection ID", + "name": "id", "in": "path" } ], "responses": { "200": { - "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", + "description": "Connection object", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiJobResultResponse" - } - } - } - }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" + "type": "object", + "properties": { + "connection": { + "type": "object", + "properties": { + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "description": "Whether branch environments override user attributes", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + } + }, + "required": [ + "connection" + ], + "description": "Get connection response", + "title": "ConnectionsGetResponse" } } } }, "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "description": "Authentication required" + }, + "403": { + "description": "Permission denied — caller lacks READ on the connection" }, "404": { - "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "description": "Connection does not exist" } } - } - }, - "/api/v1/ai/jobs/{jobId}/vis": { - "get": { - "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", - "operationId": "aiJobVisualization", - "summary": "Render AI job visualization", + }, + "patch": { + "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", + "operationId": "connectionsUpdate", + "summary": "Update connection", "tags": [ - "AI" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", + "description": "Connection ID", + "name": "id", "in": "path" } - ], + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "Default role to assign to this connection", + "example": "QUERIER" + }, + "environmentUserAttribute": { + "type": [ + "object", + "null" + ], + "properties": { + "attributeName": { + "type": "string", + "description": "Name of the user attribute for environment selection", + "example": "region" + }, + "defaultValues": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default values for the user attribute", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "attributeName", + "defaultValues" + ], + "description": "User attribute settings for connection environments" + }, + "passwordUnencrypted": { + "type": "string", + "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." + }, + "privateKey": { + "type": "string", + "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." + } + }, + "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", + "title": "ConnectionsUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "description": "Connection updated successfully", "content": { - "image/png": { + "application/json": { "schema": { - "format": "binary", - "type": "string" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing what was updated", + "example": "Updated connection default role." + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Update connection response", + "title": "ConnectionsUpdateResponse" } } } }, "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "description": "Invalid request body - at least one field must be provided" }, "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "description": "Authentication required" }, - "404": { - "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "403": { + "description": "Permission denied - connection admin role required" }, - "422": { - "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError422" - } - } - } + "404": { + "description": "Connection not found" } } - } - }, - "/api/v1/api-keys": { - "get": { - "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", - "operationId": "apiKeysList", - "summary": "List API tokens", + }, + "delete": { + "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", + "operationId": "connectionsDelete", + "summary": "Delete connection", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Cursor from the previous response (token UUID)" - }, - "required": false, - "description": "Cursor from the previous response (token UUID)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "number", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "createdAt", - "name" - ], - "default": "createdAt" - }, - "required": false, - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "personal", - "mcp" - ], - "description": "Filter by API token type. When omitted, all types are returned.", - "example": "personal" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Filter by API token type. When omitted, all types are returned.", - "name": "type", - "in": "query" + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" } ], "responses": { "200": { - "description": "Paginated list of API tokens", + "description": "Connection moved to trash", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyListResponse" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing the result", + "example": "Connection moved to trash." + }, + "success": { + "type": "boolean", + "description": "True when the connection was archived", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Archive connection response", + "title": "ConnectionsDeleteResponse" } } } }, - "400": { - "description": "Invalid query parameters" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions" + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + }, + "410": { + "description": "Connection has already been archived" } } } }, - "/api/v1/api-keys/{id}": { + "/api/v1/connections/{connectionId}/dbt": { "get": { - "description": "Returns a single API token by id. Requires organization admin permissions.", - "operationId": "apiKeysGet", - "summary": "Get API token", + "operationId": "connectionsDbtGet", + "summary": "Get dbt configuration", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", - "name": "id", + "description": "Connection ID", + "name": "connectionId", "in": "path" } ], "responses": { "200": { - "description": "The requested API token", + "description": "dbt configuration for the connection", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKey" + "anyOf": [ + { + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Whether relationships are auto-generated from dbt", + "example": true + }, + "branch": { + "type": "string", + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": "string", + "description": "dbt version being used", + "example": "Auto" + }, + "enableSemanticLayer": { + "type": "boolean", + "description": "Whether the dbt semantic layer integration is enabled", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Whether virtual schemas are enabled", + "example": false + }, + "projectRootPath": { + "type": [ + "string", + "null" + ], + "description": "Path to dbt project root", + "example": "dbt_project" + }, + "sshUrl": { + "type": "string", + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + }, + "supportsDbt": { + "type": "boolean", + "enum": [ + true + ], + "description": "Indicates dbt is supported and configured", + "example": true + } + }, + "required": [ + "autogenRelationships", + "branch", + "dbtVersion", + "enableSemanticLayer", + "enableVirtualSchemas", + "projectRootPath", + "sshUrl", + "supportsDbt" + ], + "description": "dbt repository configuration response", + "title": "DbtConfiguredResponse" + }, + { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message explaining dbt status", + "example": "dbt not configured for this connection" + }, + "supportsDbt": { + "type": "boolean", + "description": "Whether the connection dialect supports dbt", + "example": true + } + }, + "required": [ + "message", + "supportsDbt" + ], + "description": "Response when dbt is not configured", + "title": "DbtNotConfiguredResponse" + } + ], + "description": "dbt configuration response", + "title": "ConnectionsDbtGetResponse" } } } }, - "400": { - "description": "Malformed `id` (must be a UUID)" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Token not found in this organization" + "description": "Connection not found" } } }, "put": { - "description": "Enables or disables an organization-level API token. Personal access tokens and MCP OAuth grants do not support this operation. Requires organization admin permissions.", - "operationId": "apiKeysUpdate", - "summary": "Enable or disable an organization API token", + "operationId": "connectionsDbtUpdate", + "summary": "Update dbt configuration", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", - "name": "id", + "description": "Connection ID", + "name": "connectionId", "in": "path" } ], "requestBody": { - "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyUpdateBody" + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Automatically generate relationships from dbt", + "example": true + }, + "branch": { + "type": "string", + "minLength": 1, + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": [ + "string", + "null" + ], + "description": "dbt version to use. Supported: Auto, 1.10, 1.11", + "example": "1.11" + }, + "enableSemanticLayer": { + "type": "boolean", + "default": false, + "description": "Enable dbt semantic layer integration", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Enable virtual schemas from dbt", + "example": false + }, + "projectRootPath": { + "anyOf": [ + { + "type": "string", + "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" + }, + { + "type": "string", + "enum": [ + "" + ] + }, + { + "type": [ + "object", + "null" + ], + "enum": [ + null + ] + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to dbt project root within repository", + "example": "dbt_project" + }, + "rotateKeys": { + "type": "boolean", + "default": false, + "description": "Rotate SSH deploy keys", + "example": false + }, + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + } + }, + "required": [ + "autogenRelationships", + "branch", + "enableVirtualSchemas", + "sshUrl" + ], + "description": "dbt repository configuration", + "title": "ConnectionsDbtUpdateBody" } } } }, "responses": { "200": { - "description": "The updated API token", + "description": "dbt configuration updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKey" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt configuration updated successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt update response", + "title": "ConnectionsDbtUpdateResponse" } } } }, "400": { - "description": "Invalid body, malformed `id`, target is not an organization token, or missing/malformed `Authorization` header" + "description": "Invalid request body or validation error" + }, + "401": { + "description": "Authentication required" }, "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" + "description": "Connection not found" } } }, "delete": { - "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", - "operationId": "apiKeysDelete", - "summary": "Revoke an API token", + "operationId": "connectionsDbtDelete", + "summary": "Delete dbt configuration", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", - "name": "id", + "description": "Connection ID", + "name": "connectionId", "in": "path" } ], "responses": { "200": { - "description": "The token was revoked", + "description": "dbt configuration deleted successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyDeleteResponse" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt repository unlinked successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt delete response", + "title": "ConnectionsDbtDeleteResponse" } } } }, - "400": { - "description": "Malformed `id`, or missing/malformed `Authorization` header" + "401": { + "description": "Authentication required" }, "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" + "description": "Connection not found or dbt not configured" } } } }, - "/api/v1/connections": { + "/api/v1/connections/{connectionId}/dbt/environments": { "get": { - "operationId": "connectionsList", - "summary": "List connections", + "description": "List all dbt environments for a connection.", + "operationId": "connectionsDbtEnvironmentsList", + "summary": "List dbt environments", "tags": [ "Connections" ], @@ -8829,45 +32184,38 @@ { "schema": { "type": "string", - "description": "Filter by database name (case-insensitive contains)", - "example": "analytics" + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Filter by database name (case-insensitive contains)", - "name": "database", - "in": "query" + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" }, { "schema": { "type": "string", - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "example": "snowflake,bigquery" - }, - "required": false, - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "name": "dialect", - "in": "query" - }, - { - "schema": { - "type": "boolean", - "description": "Include soft-deleted connections in results", - "example": false + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" }, "required": false, - "description": "Include soft-deleted connections in results", - "name": "includeDeleted", + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", "in": "query" }, { - "schema": { - "type": "string", - "description": "Filter by connection name (case-insensitive contains)", - "example": "Production" + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 }, "required": false, - "description": "Filter by connection name (case-insensitive contains)", - "name": "name", + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", "in": "query" }, { @@ -8877,11 +32225,12 @@ "asc", "desc" ], - "description": "Sort direction", + "default": "desc", + "description": "Sort direction for results", "example": "desc" }, "required": false, - "description": "Sort direction", + "description": "Sort direction for results", "name": "sortDirection", "in": "query" }, @@ -8889,472 +32238,782 @@ "schema": { "type": "string", "enum": [ - "database", - "dialect", "name" ], - "description": "Field to sort by", + "default": "name", + "description": "Field to sort results by", "example": "name" }, "required": false, - "description": "Field to sort by", + "description": "Field to sort results by", "name": "sortField", "in": "query" } ], "responses": { "200": { - "description": "List of connections", + "description": "List of dbt environments", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseRole": { - "type": [ - "string", - "null" - ], - "description": "Default role for users on this connection", - "example": "QUERIER" - }, - "branchConnectionEnvironmentOverridesUserAttr": { - "type": [ - "boolean", - "null" - ], - "description": "Whether branch environments override user attributes", - "example": false - }, - "database": { - "type": [ - "string", - "null" - ], - "description": "Database name", - "example": "analytics_db" - }, - "defaultSchema": { - "type": [ - "string", - "null" - ], - "description": "Default schema for the connection", - "example": "public" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when connection was deleted (ISO 8601)", - "example": null - }, - "dialect": { - "type": "string", - "enum": [ - "snowflake", - "bigquery", - "redshift", - "postgres", - "mysql", - "mariadb", - "databricks", - "databricks_lakebase", - "trino", - "athena", - "duckdb", - "motherduck", - "sqlserver", - "clickhouse", - "singlestore" - ], - "description": "Database dialect type", - "example": "snowflake" - }, - "environmentConnectionSwitchesSchemaModel": { - "type": [ - "boolean", - "null" - ], - "description": "Whether environment connections switch schema model", - "example": false - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection identifier", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "name": { - "type": "string", - "description": "Connection display name", - "example": "Production Snowflake" - }, - "userAttributeNameForConnectionsEnvironments": { - "type": [ - "string", - "null" - ], - "description": "User attribute name used for connection environments", - "example": "region" - }, - "userAttributeValuesForDefaultEnvironment": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default user attribute values for the base environment", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "baseRole", - "branchConnectionEnvironmentOverridesUserAttr", - "database", - "defaultSchema", - "deletedAt", - "dialect", - "environmentConnectionSwitchesSchemaModel", - "id", - "name", - "userAttributeNameForConnectionsEnvironments", - "userAttributeValuesForDefaultEnvironment" - ], - "description": "Connection object", - "title": "Connection" - }, - "description": "List of connections" + "$ref": "#/components/schemas/DbtEnvironmentListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection not found" + } + } + }, + "post": { + "description": "Create a new dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsCreate", + "summary": "Create dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "dbt environment created successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" + }, + { + "description": "Created dbt environment", + "title": "DbtEnvironmentCreateResponse" + } + ] + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { + "put": { + "description": "Update an existing dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsUpdate", + "summary": "Update dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt environment updated successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" + }, + { + "description": "Updated dbt environment", + "title": "DbtEnvironmentUpdateResponse" } - }, - "required": [ - "connections" - ], - "description": "List connections response", - "title": "ConnectionsListResponse" + ] } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" } } }, - "post": { - "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", - "operationId": "connectionsCreate", - "summary": "Create connection", + "delete": { + "description": "Delete a dbt environment from a connection.", + "operationId": "connectionsDbtEnvironmentsDelete", + "summary": "Delete dbt environment", "tags": [ "Connections" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "acceptsLicense": { - "type": "boolean", - "description": "Acceptance of the license terms. Required for Oracle connections.", - "example": true - }, - "allowsUserSpecificTimezones": { - "type": "boolean", - "default": false, - "description": "Whether to allow users to specify their own timezones", - "example": false - }, - "alwaysScopeViewNames": { - "type": "boolean", - "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", - "example": true - }, - "authenticationType": { - "type": "string", - "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", - "example": "snowflake-password" - }, - "awsRoleArn": { - "type": "string", - "description": "AWS IAM role ARN. Applicable for Athena only.", - "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" - }, - "baseRole": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "RESTRICTED_QUERIER", - "QUERIER", - "MODELER", - "CONNECTION_ADMIN" - ], - "description": "The default role for users accessing the connection", - "example": "QUERIER" - }, - "database": { - "type": "string", - "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", - "example": "analytics_db" - }, - "defaultSchema": { - "type": "string", - "description": "The default schema to use. Required for MSSQL.", - "example": "public" - }, - "dialect": { - "type": "string", - "enum": [ - "athena", - "bigquery", - "clickhouse", - "databricks", - "databricks_lakebase", - "exasol", - "mariadb", - "motherduck", - "mssql", - "mysql", - "oracle", - "postgres", - "redshift", - "sap_hana", - "snowflake", - "starrocks", - "trino" - ], - "description": "The database dialect", - "example": "snowflake" - }, - "enableDbSemanticLayerIntegration": { - "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", - "example": false - }, - "enableDbSemanticLayerTopics": { - "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", - "example": false - }, - "externalOauthAudience": { - "type": "string", - "description": "External OAuth audience claim. Applicable for Snowflake." - }, - "externalOauthAuthorizationUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/authorize" - }, - "externalOauthTokenUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/token" - }, - "host": { - "type": "string", - "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", - "example": "myaccount" - }, - "hostOverride": { - "type": "string", - "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", - "example": "myaccount.snowflakecomputing.com" - }, - "includeOtherCatalogs": { - "type": "string", - "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", - "example": "other_project1,other_project2" - }, - "includeSchemas": { - "type": "string", - "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", - "example": "public,analytics" - }, - "inferRelationshipsFromColumnNames": { - "type": "boolean", - "default": true, - "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", - "example": true + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt environment deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/schedules": { + "get": { + "operationId": "connectionsSchedulesList", + "summary": "List schema refresh schedules", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "List of schema refresh schedules", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schedules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Schema refresh schedule object", + "title": "ConnectionSchedule" + }, + "description": "List of schema refresh schedules" + } }, - "inferRelationshipsFromForeignKeys": { + "required": [ + "schedules" + ], + "description": "List schedules response", + "title": "ConnectionsSchedulesListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "post": { + "operationId": "connectionsSchedulesCreate", + "summary": "Create schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { "type": "boolean", "default": false, - "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", "example": false }, - "maxBillingBytes": { - "type": "string", - "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", - "example": "1000000000" - }, - "name": { - "type": "string", - "description": "A descriptive name for the connection", - "example": "Production Warehouse" - }, - "oauthClientId": { - "type": "string", - "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." - }, - "oauthClientSecretUnencrypted": { - "type": "string", - "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." - }, - "offloadedSchemas": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", - "example": [ - "analytics_archive" - ] - }, - "passwordUnencrypted": { - "type": "string", - "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." - }, - "port": { - "type": "integer", - "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", - "example": 5432 - }, - "privateKey": { - "type": "string", - "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." - }, - "queryTimeoutSeconds": { - "type": "integer", - "maximum": 3600, - "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", - "example": 900 - }, - "queryTimezone": { - "type": "string", - "description": "The timezone to use for queries", - "example": "NONE" - }, - "region": { + "schedule": { "type": "string", - "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", - "example": "us-east-1" + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" }, - "scratchSchema": { + "timezone": { "type": "string", - "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", - "example": "omni_scratch" + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for creating a schema refresh schedule", + "title": "ConnectionsSchedulesCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Schema refresh schedule created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } }, - "systemTimezone": { - "type": "string", - "description": "The timezone to use for the system", - "example": "UTC" + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Created schedule response", + "title": "ConnectionsSchedulesCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid cron expression or timezone" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { + "get": { + "operationId": "connectionsSchedulesGet", + "summary": "Get schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schema refresh schedule details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } }, - "trustServerCertificate": { + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Get schedule response", + "title": "ConnectionsSchedulesGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" + } + } + }, + "put": { + "operationId": "connectionsSchedulesUpdate", + "summary": "Update schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { "type": "boolean", "default": false, - "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", - "example": false - }, - "useMachineAuth": { - "type": "boolean", - "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", "example": false }, - "username": { + "schedule": { "type": "string", - "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", - "example": "analytics_user" + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" }, - "warehouse": { + "timezone": { "type": "string", - "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path).", - "example": "COMPUTE_WH" + "description": "IANA timezone for schedule execution", + "example": "America/New_York" } }, "required": [ - "dialect", - "name", - "passwordUnencrypted" + "schedule", + "timezone" ], - "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", - "title": "ConnectionsCreateBody" + "description": "Request body for updating a schema refresh schedule", + "title": "ConnectionsSchedulesUpdateBody" } } } }, "responses": { - "201": { - "description": "Connection created successfully", + "200": { + "description": "Schema refresh schedule updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "data": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { "type": "string", "format": "uuid", - "description": "Created connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" } }, "required": [ - "data", - "success" + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" ], - "description": "Create connection response", - "title": "ConnectionsCreateResponse" + "description": "Updated schedule response", + "title": "ConnectionsSchedulesUpdateResponse" } } } }, "400": { - "description": "Invalid request body or dialect" + "description": "Invalid cron expression or timezone" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" } } - } - }, - "/api/v1/connections/{id}": { - "patch": { - "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", - "operationId": "connectionsUpdate", - "summary": "Update connection", + }, + "delete": { + "operationId": "connectionsSchedulesDelete", + "summary": "Delete schema refresh schedule", "tags": [ "Connections" ], @@ -9368,81 +33027,30 @@ }, "required": true, "description": "Connection ID", - "name": "id", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "Default role to assign to this connection", - "example": "QUERIER" - }, - "environmentUserAttribute": { - "type": [ - "object", - "null" - ], - "properties": { - "attributeName": { - "type": "string", - "description": "Name of the user attribute for environment selection", - "example": "region" - }, - "defaultValues": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default values for the user attribute", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "attributeName", - "defaultValues" - ], - "description": "User attribute settings for connection environments" - }, - "passwordUnencrypted": { - "type": "string", - "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." - }, - "privateKey": { - "type": "string", - "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." - } - }, - "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", - "title": "ConnectionsUpdateBody" - } - } - } - }, "responses": { "200": { - "description": "Connection updated successfully", + "description": "Schema refresh schedule deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "Status message describing what was updated", - "example": "Updated connection default role." - }, "success": { "type": "boolean", "description": "Whether the operation succeeded", @@ -9450,18 +33058,14 @@ } }, "required": [ - "message", "success" ], - "description": "Update connection response", - "title": "ConnectionsUpdateResponse" + "description": "Delete schedule response", + "title": "ConnectionsSchedulesDeleteResponse" } } } }, - "400": { - "description": "Invalid request body - at least one field must be provided" - }, "401": { "description": "Authentication required" }, @@ -9469,144 +33073,214 @@ "description": "Permission denied - connection admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection or schedule not found" } } } }, - "/api/v1/connections/{connectionId}/dbt": { + "/api/v1/connection-environments": { "get": { - "operationId": "connectionsDbtGet", - "summary": "Get dbt configuration", + "operationId": "connectionEnvironmentsList", + "summary": "List connection environments", "tags": [ "Connections" ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "responses": { + "200": { + "description": "List of connection environments", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" + }, + "description": "List of connection environments" + } + }, + "required": [ + "connectionEnvironments" + ], + "description": "List connection environments response", + "title": "ConnectionsEnvironmentsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + }, + "post": { + "operationId": "connectionEnvironmentsCreate", + "summary": "Create connection environments", + "tags": [ + "Connections" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "environmentConnectionIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "IDs of connections to use as environments", + "example": [ + "550e8400-e29b-41d4-a716-446655440002", + "550e8400-e29b-41d4-a716-446655440003" + ] + } + }, + "required": [ + "baseConnectionId", + "environmentConnectionIds" + ], + "description": "Request body for creating connection environments", + "title": "ConnectionsEnvironmentsCreateBody" + } + } } - ], + }, "responses": { - "200": { - "description": "dbt configuration for the connection", + "201": { + "description": "Connection environments created successfully", "content": { "application/json": { "schema": { - "anyOf": [ - { - "type": "object", - "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Whether relationships are auto-generated from dbt", - "example": true - }, - "branch": { - "type": "string", - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": "string", - "description": "dbt version being used", - "example": "Auto" - }, - "enableSemanticLayer": { - "type": "boolean", - "description": "Whether the dbt semantic layer integration is enabled", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Whether virtual schemas are enabled", - "example": false - }, - "projectRootPath": { - "type": [ - "string", - "null" - ], - "description": "Path to dbt project root", - "example": "dbt_project" - }, - "sshUrl": { - "type": "string", - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" - }, - "supportsDbt": { - "type": "boolean", - "enum": [ - true - ], - "description": "Indicates dbt is supported and configured", - "example": true - } - }, - "required": [ - "autogenRelationships", - "branch", - "dbtVersion", - "enableSemanticLayer", - "enableVirtualSchemas", - "projectRootPath", - "sshUrl", - "supportsDbt" - ], - "description": "dbt repository configuration response", - "title": "DbtConfiguredResponse" - }, - { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Message explaining dbt status", - "example": "dbt not configured for this connection" + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } }, - "supportsDbt": { - "type": "boolean", - "description": "Whether the connection dialect supports dbt", - "example": true - } + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" }, - "required": [ - "message", - "supportsDbt" - ], - "description": "Response when dbt is not configured", - "title": "DbtNotConfiguredResponse" + "description": "Created connection environments" } + }, + "required": [ + "connectionEnvironments" ], - "description": "dbt configuration response", - "title": "ConnectionsDbtGetResponse" + "description": "Create connection environments response", + "title": "ConnectionsEnvironmentsCreateResponse" } } } }, + "400": { + "description": "Invalid request body or connection IDs" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found" + "description": "Base connection or environment connection not found" } } - }, + } + }, + "/api/v1/connection-environments/{id}": { "put": { - "operationId": "connectionsDbtUpdate", - "summary": "Update dbt configuration", + "operationId": "connectionEnvironmentsUpdate", + "summary": "Update connection environment", "tags": [ "Connections" ], @@ -9615,12 +33289,12 @@ "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Connection environment ID", + "name": "id", "in": "path" } ], @@ -9630,103 +33304,35 @@ "schema": { "type": "object", "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Automatically generate relationships from dbt", - "example": true - }, - "branch": { - "type": "string", - "minLength": 1, - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": [ - "string", - "null" - ], - "description": "dbt version to use. Supported: Auto, 1.10, 1.11", - "example": "1.11" - }, - "enableSemanticLayer": { - "type": "boolean", - "default": false, - "description": "Enable dbt semantic layer integration", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Enable virtual schemas from dbt", - "example": false - }, - "projectRootPath": { - "anyOf": [ - { - "type": "string", - "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" - }, - { - "type": "string", - "enum": [ - "" - ] - }, - { - "type": [ - "object", - "null" - ], - "enum": [ - null - ] - }, - { - "type": "null" - } - ], - "default": null, - "description": "Path to dbt project root within repository", - "example": "dbt_project" - }, - "rotateKeys": { - "type": "boolean", - "default": false, - "description": "Rotate SSH deploy keys", - "example": false - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] } }, "required": [ - "autogenRelationships", - "branch", - "enableVirtualSchemas", - "sshUrl" + "userAttributeValues" ], - "description": "dbt repository configuration", - "title": "ConnectionsDbtUpdateBody" + "description": "Request body for updating a connection environment", + "title": "ConnectionsEnvironmentsUpdateBody" } } } }, "responses": { "200": { - "description": "dbt configuration updated successfully", + "description": "Connection environment updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "dbt configuration updated successfully" - }, "success": { "type": "boolean", "description": "Whether the operation succeeded", @@ -9734,32 +33340,31 @@ } }, "required": [ - "message", "success" ], - "description": "dbt update response", - "title": "ConnectionsDbtUpdateResponse" + "description": "Update connection environment response", + "title": "ConnectionsEnvironmentsUpdateResponse" } } } }, "400": { - "description": "Invalid request body or validation error" + "description": "Invalid request body" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection environment not found" } } }, "delete": { - "operationId": "connectionsDbtDelete", - "summary": "Delete dbt configuration", + "operationId": "connectionEnvironmentsDelete", + "summary": "Delete connection environment", "tags": [ "Connections" ], @@ -9768,28 +33373,23 @@ "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Connection environment ID", + "name": "id", "in": "path" } ], "responses": { "200": { - "description": "dbt configuration deleted successfully", + "description": "Connection environment deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "dbt repository unlinked successfully" - }, "success": { "type": "boolean", "description": "Whether the operation succeeded", @@ -9797,11 +33397,10 @@ } }, "required": [ - "message", "success" ], - "description": "dbt delete response", - "title": "ConnectionsDbtDeleteResponse" + "description": "Delete connection environment response", + "title": "ConnectionsEnvironmentsDeleteResponse" } } } @@ -9810,35 +33409,22 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found or dbt not configured" + "description": "Connection environment not found" } } } }, - "/api/v1/connections/{connectionId}/dbt/environments": { + "/api/v1/content": { "get": { - "description": "List all dbt environments for a connection.", - "operationId": "connectionsDbtEnvironmentsList", - "summary": "List dbt environments", + "operationId": "contentList", + "summary": "List content", "tags": [ - "Connections" + "Content" ], "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, { "schema": { "type": "string", @@ -9852,617 +33438,359 @@ }, { "schema": { - "type": "number", + "type": "integer", "minimum": 1, "maximum": 100, "default": 20, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "example": 20 }, "required": false, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "name": "pageSize", "in": "query" }, { "schema": { "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name" - ], - "default": "name", - "description": "Field to sort results by", - "example": "name" + "format": "uuid", + "description": "Filter by creator user ID" }, "required": false, - "description": "Field to sort results by", - "name": "sortField", + "description": "Filter by creator user ID", + "name": "creatorId", "in": "query" - } - ], - "responses": { - "200": { - "description": "List of dbt environments", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection not found" - } - } - }, - "post": { - "description": "Create a new dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsCreate", - "summary": "Create dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "dbt environment created successfully", - "content": { - "application/json": { - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentItem" - }, - { - "description": "Created dbt environment", - "title": "DbtEnvironmentCreateResponse" - } - ] - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection not found" - } - } - } - }, - "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { - "put": { - "description": "Update an existing dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsUpdate", - "summary": "Update dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + "description": "Filter by folder ID (cannot be used with path)" }, - "required": true, - "description": "Environment ID", - "name": "environmentId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "dbt environment updated successfully", - "content": { - "application/json": { - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentItem" - }, - { - "description": "Updated dbt environment", - "title": "DbtEnvironmentUpdateResponse" - } - ] - } - } - } + "required": false, + "description": "Filter by folder ID (cannot be used with path)", + "name": "folderId", + "in": "query" }, - "400": { - "description": "Invalid request body" + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (e.g., _count,labels)" + }, + "required": false, + "description": "Comma-separated list of fields to include (e.g., _count,labels)", + "name": "include", + "in": "query" }, - "401": { - "description": "Authentication required" + { + "schema": { + "type": "string", + "description": "Filter by folder path (cannot be used with folderId)", + "example": "/reports/sales" + }, + "required": false, + "description": "Filter by folder path (cannot be used with folderId)", + "name": "path", + "in": "query" }, - "403": { - "description": "Permission denied or connection does not support dbt" + { + "schema": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Filter by share scope", + "example": "organization" + }, + "required": false, + "description": "Filter by share scope", + "name": "scope", + "in": "query" }, - "404": { - "description": "Connection or environment not found" - } - } - }, - "delete": { - "description": "Delete a dbt environment from a connection.", - "operationId": "connectionsDbtEnvironmentsDelete", - "summary": "Delete dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "asc" }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + "enum": [ + "name", + "favorites" + ], + "description": "Field to sort by", + "example": "name" }, - "required": true, - "description": "Environment ID", - "name": "environmentId", - "in": "path" + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" } ], "responses": { "200": { - "description": "dbt environment deleted successfully", + "description": "List of content (documents and folders)", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + "$ref": "#/components/schemas/ContentListResponse" } } } }, + "400": { + "description": "Invalid query parameters (cannot use both folderId and path)" + }, "401": { "description": "Authentication required" }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, "404": { - "description": "Connection or environment not found" + "description": "Folder not found (when filtering by path)" } } } }, - "/api/v1/connections/{connectionId}/schedules": { - "get": { - "operationId": "connectionsSchedulesList", - "summary": "List schema refresh schedules", + "/api/v1/dashboards/{identifier}/download": { + "post": { + "operationId": "dashboardsDownload", + "summary": "Initiate dashboard download", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" - } - ], - "responses": { - "200": { - "description": "List of schema refresh schedules", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Schema refresh schedule object", - "title": "ConnectionSchedule" - }, - "description": "List of schema refresh schedules" - } - }, - "required": [ - "schedules" - ], - "description": "List schedules response", - "title": "ConnectionsSchedulesListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" }, - "404": { - "description": "Connection not found" - } - } - }, - "post": { - "operationId": "connectionsSchedulesCreate", - "summary": "Create schema refresh schedule", - "tags": [ - "Connections" - ], - "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Target user membership ID (for org-scoped API keys)" }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for creating a schema refresh schedule", - "title": "ConnectionsSchedulesCreateBody" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsDownloadBody" } } } }, "responses": { - "201": { - "description": "Schema refresh schedule created successfully", + "200": { + "description": "Download job initiated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Created schedule response", - "title": "ConnectionsSchedulesCreateResponse" + "$ref": "#/components/schemas/DashboardsDownloadResponse" } } } }, "400": { - "description": "Invalid cron expression or timezone" + "description": "Invalid request body or filter configuration" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - cannot download this dashboard" }, "404": { - "description": "Connection not found" + "description": "Dashboard not found" + }, + "409": { + "description": "Download already in progress for this dashboard" + }, + "500": { + "description": "Failed to initiate download" } } } }, - "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { + "/api/v1/dashboards/{identifier}/download/{jobId}": { "get": { - "operationId": "connectionsSchedulesGet", - "summary": "Get schema refresh schedule", + "operationId": "dashboardsDownloadFile", + "summary": "Get download file", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "File ready - binary content streamed" + }, + "202": { + "description": "Download job still in progress" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Dashboard or download job not found" + }, + "410": { + "description": "Download job failed" + }, + "500": { + "description": "Failed to retrieve download artifact" + } + } + } + }, + "/api/v1/dashboards/{identifier}/download/{jobId}/status": { + "get": { + "operationId": "dashboardsDownloadStatus", + "summary": "Get download job status", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Schedule ID", - "name": "scheduleId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "responses": { "200": { - "description": "Schema refresh schedule details", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Get schedule response", - "title": "ConnectionsSchedulesGetResponse" + "description": "Download job status" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Dashboard or download job not found" + } + } + } + }, + "/api/v1/dashboards/{identifier}/filters": { + "get": { + "operationId": "dashboardsGetFilters", + "summary": "Get dashboard filters", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Dashboard filter and control configuration", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardFiltersResponse" } } } @@ -10471,440 +33799,319 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - VIEWER role required" }, "404": { - "description": "Connection or schedule not found" + "description": "Dashboard not found" } } }, - "put": { - "operationId": "connectionsSchedulesUpdate", - "summary": "Update schema refresh schedule", + "patch": { + "operationId": "dashboardsUpdateFilters", + "summary": "Update dashboard filters", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Target user membership ID (for org-scoped API keys)" }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for updating a schema refresh schedule", - "title": "ConnectionsSchedulesUpdateBody" + "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" } } } }, "responses": { "200": { - "description": "Schema refresh schedule updated successfully", + "description": "Filters updated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Updated schedule response", - "title": "ConnectionsSchedulesUpdateResponse" + "$ref": "#/components/schemas/DashboardFiltersResponse" } } } }, "400": { - "description": "Invalid cron expression or timezone" + "description": "Invalid request body - must include at least one filter, control, or filterOrder" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - EDITOR role required" }, "404": { - "description": "Connection or schedule not found" + "description": "Dashboard not found or document does not have a dashboard" + }, + "409": { + "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." } } - }, - "delete": { - "operationId": "connectionsSchedulesDelete", - "summary": "Delete schema refresh schedule", + } + }, + "/api/v1/documents": { + "get": { + "operationId": "documentsList", + "summary": "List documents", "tags": [ - "Connections" + "Documents" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Filter by creator membership ID" + }, + "required": false, + "description": "Filter by creator membership ID", + "name": "creatorId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by folder ID" + }, + "required": false, + "description": "Filter by folder ID", + "name": "folderId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "example": "_count,labels" + }, + "required": false, + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of label names to filter by", + "example": "verified,important" + }, + "required": false, + "description": "Comma-separated list of label names to filter by", + "name": "labels", + "in": "query" + }, + { + "schema": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 50, + "description": "Number of records per page" + }, + "required": false, + "description": "Number of records per page", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "favorites", + "updatedAt", + "visits" + ], + "default": "name", + "description": "Field to sort by" }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" }, { "schema": { "type": "string", "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Filter documents visible to this membership ID" }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" + "required": false, + "description": "Filter documents visible to this membership ID", + "name": "userId", + "in": "query" } ], "responses": { "200": { - "description": "Schema refresh schedule deleted successfully", + "description": "Paginated list of documents", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete schedule response", - "title": "ConnectionsSchedulesDeleteResponse" + "$ref": "#/components/schemas/DocumentsListResponse" } } } }, "401": { "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection or schedule not found" } } - } - }, - "/api/v1/connection-environments": { - "get": { - "operationId": "connectionEnvironmentsList", - "summary": "List connection environments", + }, + "post": { + "operationId": "documentsCreate", + "summary": "Create document", "tags": [ - "Connections" + "Documents" ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateBody" + } + } + } + }, "responses": { - "200": { - "description": "List of connection environments", + "201": { + "description": "Document created successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "List of connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "List connection environments response", - "title": "ConnectionsEnvironmentsListResponse" + "$ref": "#/components/schemas/DocumentsCreateResponse" } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" } } - }, - "post": { - "operationId": "connectionEnvironmentsCreate", - "summary": "Create connection environments", + } + }, + "/api/v1/documents/{identifier}": { + "get": { + "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", + "operationId": "documentsGet", + "summary": "Get document", "tags": [ - "Connections" + "Documents" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "environmentConnectionIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "IDs of connections to use as environments", - "example": [ - "550e8400-e29b-41d4-a716-446655440002", - "550e8400-e29b-41d4-a716-446655440003" - ] - } - }, - "required": [ - "baseConnectionId", - "environmentConnectionIds" - ], - "description": "Request body for creating connection environments", - "title": "ConnectionsEnvironmentsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Connection environments created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "Created connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "Create connection environments response", - "title": "ConnectionsEnvironmentsCreateResponse" + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Document details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetResponse" } } } }, "400": { - "description": "Invalid request body or connection IDs" + "description": "Analysis documents are not supported" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Insufficient permissions to view the document" }, "404": { - "description": "Base connection or environment connection not found" + "description": "Document not found" } } - } - }, - "/api/v1/connection-environments/{id}": { + }, "put": { - "operationId": "connectionEnvironmentsUpdate", - "summary": "Update connection environment", + "description": "Updates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", + "operationId": "documentsPut", + "summary": "Replace document (full replacement)", "tags": [ - "Connections" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Connection environment ID", - "name": "id", + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", "in": "path" } ], @@ -10912,577 +34119,506 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "userAttributeValues" - ], - "description": "Request body for updating a connection environment", - "title": "ConnectionsEnvironmentsUpdateBody" + "$ref": "#/components/schemas/DocumentsPutBody" } } } }, "responses": { "200": { - "description": "Connection environment updated successfully", + "description": "Document replaced successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Update connection environment response", - "title": "ConnectionsEnvironmentsUpdateResponse" + "$ref": "#/components/schemas/DocumentsPutResponse" } } } }, "400": { - "description": "Invalid request body" + "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Insufficient permissions to update the document" }, "404": { - "description": "Connection environment not found" + "description": "Document not found" + }, + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } }, - "delete": { - "operationId": "connectionEnvironmentsDelete", - "summary": "Delete connection environment", + "patch": { + "description": "Updates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", + "operationId": "documentsUpdate", + "summary": "Rename document", "tags": [ - "Connections" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Connection environment ID", - "name": "id", + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "Connection environment deleted successfully", + "description": "Document updated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete connection environment response", - "title": "ConnectionsEnvironmentsDeleteResponse" + "$ref": "#/components/schemas/DocumentsUpdateResponse" } } } }, + "400": { + "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - EDITOR role required" }, "404": { - "description": "Connection environment not found" + "description": "Document not found" + }, + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } - } - }, - "/api/v1/content": { - "get": { - "operationId": "contentList", - "summary": "List content", + }, + "delete": { + "operationId": "documentsDelete", + "summary": "Delete document", "tags": [ - "Content" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "number", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by creator user ID" - }, - "required": false, - "description": "Filter by creator user ID", - "name": "creatorId", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by folder ID (cannot be used with path)" - }, - "required": false, - "description": "Filter by folder ID (cannot be used with path)", - "name": "folderId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of fields to include (e.g., _count,labels)" - }, - "required": false, - "description": "Comma-separated list of fields to include (e.g., _count,labels)", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by folder path (cannot be used with folderId)", - "example": "/reports/sales" - }, - "required": false, - "description": "Filter by folder path (cannot be used with folderId)", - "name": "path", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Filter by share scope", - "example": "organization" - }, - "required": false, - "description": "Filter by share scope", - "name": "scope", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "description": "Sort direction", - "example": "asc" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "favorites" - ], - "description": "Field to sort by", - "example": "name" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], "responses": { "200": { - "description": "List of content (documents and folders)", + "description": "Document deleted successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ContentListResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, - "400": { - "description": "Invalid query parameters (cannot use both folderId and path)" - }, "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - MANAGER role required" + }, "404": { - "description": "Folder not found (when filtering by path)" + "description": "Document not found" } } } }, - "/api/v1/dashboards/{identifier}/download": { - "post": { - "operationId": "dashboardsDownload", - "summary": "Initiate dashboard download", + "/api/v1/documents/{identifier}/queries": { + "get": { + "operationId": "documentsGetQueries", + "summary": "List document queries", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + } + ], + "responses": { + "200": { + "description": "List of queries in the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetQueriesResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/move": { + "put": { + "operationId": "documentsMove", + "summary": "Move document", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsDownloadBody" + "$ref": "#/components/schemas/DocumentsMoveBody" } } } }, "responses": { "200": { - "description": "Download job initiated successfully", + "description": "Document moved successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsDownloadResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body or filter configuration" + "description": "Invalid folder path or scope" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - cannot download this dashboard" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Dashboard not found" - }, - "409": { - "description": "Download already in progress for this dashboard" - }, - "500": { - "description": "Failed to initiate download" + "description": "Document or folder not found" } } } }, - "/api/v1/dashboards/{identifier}/download/{jobId}": { + "/api/v1/documents/{identifier}/permissions": { "get": { - "operationId": "dashboardsDownloadFile", - "summary": "Get download file", + "operationId": "documentsGetPermissions", + "summary": "Get document permissions", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" }, { "schema": { "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" + "format": "uuid", + "description": "User membership ID to check permissions for" }, "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", + "description": "User membership ID to check permissions for", "name": "userId", "in": "query" } ], "responses": { "200": { - "description": "File ready - binary content streamed" - }, - "202": { - "description": "Download job still in progress" + "description": "User permissions for the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" + } + } + } }, "401": { "description": "Authentication required" }, - "404": { - "description": "Dashboard or download job not found" - }, - "410": { - "description": "Download job failed" + "403": { + "description": "Permission denied" }, - "500": { - "description": "Failed to retrieve download artifact" + "404": { + "description": "Document or user not found" } } - } - }, - "/api/v1/dashboards/{identifier}/download/{jobId}/status": { - "get": { - "operationId": "dashboardsDownloadStatus", - "summary": "Get download job status", + }, + "put": { + "operationId": "documentsUpdatePermissionSettings", + "summary": "Update document permission settings", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permission settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" }, + "404": { + "description": "Document not found" + } + } + }, + "post": { + "operationId": "documentsAddPermits", + "summary": "Add document permits", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsAddPermitsBody" + } + } + } + }, "responses": { "200": { - "description": "Download job status" + "description": "Permissions added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - MANAGER role required" + }, "404": { - "description": "Dashboard or download job not found" + "description": "Document not found" } } - } - }, - "/api/v1/dashboards/{identifier}/filters": { - "get": { - "operationId": "dashboardsGetFilters", - "summary": "Get dashboard filters", + }, + "patch": { + "operationId": "documentsUpdatePermits", + "summary": "Update document permits", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" + } + } + } + }, "responses": { "200": { - "description": "Dashboard filter and control configuration", + "description": "Permissions updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - VIEWER role required" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Dashboard not found" + "description": "Document not found" } } }, - "patch": { - "operationId": "dashboardsUpdateFilters", - "summary": "Update dashboard filters", + "delete": { + "operationId": "documentsRevokePermits", + "summary": "Revoke document permits", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" + "$ref": "#/components/schemas/DocumentsRevokePermitsBody" } } } }, "responses": { "200": { - "description": "Filters updated successfully", + "description": "Permissions revoked successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body - must include at least one filter, control, or filterOrder" + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Dashboard not found or document does not have a dashboard" - }, - "409": { - "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." + "description": "Document not found" } } } }, - "/api/v1/documents": { - "get": { - "operationId": "documentsList", - "summary": "List documents", + "/api/v1/documents/{identifier}/draft": { + "post": { + "operationId": "documentsCreateDraft", + "summary": "Create document draft", "tags": [ "Documents" ], @@ -11490,158 +34626,88 @@ { "schema": { "type": "string", - "format": "uuid", - "description": "Filter by creator membership ID" - }, - "required": false, - "description": "Filter by creator membership ID", - "name": "creatorId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination" - }, - "required": false, - "description": "Cursor for pagination", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by folder ID" - }, - "required": false, - "description": "Filter by folder ID", - "name": "folderId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "example": "_count,labels" - }, - "required": false, - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of label names to filter by", - "example": "verified,important" - }, - "required": false, - "description": "Comma-separated list of label names to filter by", - "name": "labels", - "in": "query" - }, - { - "schema": { - "type": "integer", - "exclusiveMinimum": 0, - "default": 50, - "description": "Number of records per page" - }, - "required": false, - "description": "Number of records per page", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "favorites", - "updatedAt", - "visits" - ], - "default": "name", - "description": "Field to sort by" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter documents visible to this membership ID" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Filter documents visible to this membership ID", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateDraftBody" + } + } + } + }, "responses": { "200": { - "description": "Paginated list of documents", + "description": "Draft created or existing draft returned", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsListResponse" + "$ref": "#/components/schemas/DocumentsCreateDraftResponse" } } } }, + "400": { + "description": "Document is not eligible for publishing workflow" + }, "401": { "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Document or branch not found" } } }, - "post": { - "operationId": "documentsCreate", - "summary": "Create document", + "delete": { + "operationId": "documentsDiscardDraft", + "summary": "Discard document draft", "tags": [ "Documents" ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateBody" + "$ref": "#/components/schemas/DocumentsDiscardDraftBody" } } } }, "responses": { - "201": { - "description": "Document created successfully", + "200": { + "description": "Draft discarded successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateResponse" + "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" } } } }, - "400": { - "description": "Invalid request body" - }, "401": { "description": "Authentication required" }, @@ -11649,16 +34715,16 @@ "description": "Permission denied" }, "404": { - "description": "Model or branch not found" + "description": "Document or draft not found" } } } }, - "/api/v1/documents/{identifier}": { - "get": { - "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", - "operationId": "documentsGet", - "summary": "Get document", + "/api/v1/documents/{identifier}/drafts": { + "get": { + "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", + "operationId": "documentsListDrafts", + "summary": "List document drafts", "tags": [ "Documents" ], @@ -11673,21 +34739,32 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "example": "archived" + }, + "required": false, + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "name": "include", + "in": "query" } ], "responses": { "200": { - "description": "Document details", + "description": "List of drafts for the document", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsGetResponse" + "$ref": "#/components/schemas/DocumentsListDraftsResponse" } } } }, "400": { - "description": "Analysis documents are not supported" + "description": "Invalid query parameters" }, "401": { "description": "Authentication required" @@ -11699,11 +34776,12 @@ "description": "Document not found" } } - }, - "put": { - "description": "Updates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", - "operationId": "documentsPut", - "summary": "Replace document (full replacement)", + } + }, + "/api/v1/documents/{identifier}/duplicate": { + "post": { + "operationId": "documentsDuplicate", + "summary": "Duplicate document", "tags": [ "Documents" ], @@ -11718,49 +34796,58 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsPutBody" + "$ref": "#/components/schemas/DocumentsDuplicateBody" } } } }, "responses": { - "200": { - "description": "Document replaced successfully", + "201": { + "description": "Document duplicated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsPutResponse" + "$ref": "#/components/schemas/DocumentsDuplicateResponse" } } } }, "400": { - "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" + "description": "Invalid name or folder path" }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions to update the document" + "description": "Permission denied" }, "404": { - "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" + "description": "Document or folder not found" } } - }, - "patch": { - "description": "Updates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", - "operationId": "documentsUpdate", - "summary": "Rename document", + } + }, + "/api/v1/documents/{identifier}/favorite": { + "put": { + "operationId": "documentsAddFavorite", + "summary": "Add document to favorites", "tags": [ "Documents" ], @@ -11775,48 +34862,37 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdateBody" - } - } - } - }, "responses": { - "200": { - "description": "Document updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" + "204": { + "description": "Favorite added successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Permission denied" }, "404": { "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } }, "delete": { - "operationId": "documentsDelete", - "summary": "Delete document", + "operationId": "documentsRemoveFavorite", + "summary": "Remove document from favorites", "tags": [ "Documents" ], @@ -11831,24 +34907,28 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "responses": { - "200": { - "description": "Document deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } + "204": { + "description": "Favorite removed successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document not found" @@ -11856,10 +34936,10 @@ } } }, - "/api/v1/documents/{identifier}/queries": { - "get": { - "operationId": "documentsGetQueries", - "summary": "List document queries", + "/api/v1/documents/{identifier}/labels": { + "patch": { + "operationId": "documentsBulkUpdateLabels", + "summary": "Bulk update document labels", "tags": [ "Documents" ], @@ -11874,19 +34954,42 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" + } + } + } + }, "responses": { "200": { - "description": "List of queries in the document", + "description": "Labels updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsGetQueriesResponse" + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" } } } }, + "400": { + "description": "Invalid request - at least one label must be specified" + }, "401": { "description": "Authentication required" }, @@ -11899,10 +35002,10 @@ } } }, - "/api/v1/documents/{identifier}/move": { - "post": { - "operationId": "documentsMove", - "summary": "Move document", + "/api/v1/documents/{identifier}/labels/{labelName}": { + "put": { + "operationId": "documentsAddLabel", + "summary": "Add label to document", "tags": [ "Documents" ], @@ -11910,54 +35013,55 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsMoveBody" - } - } - } - }, "responses": { - "200": { - "description": "Document moved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid folder path or scope" + "204": { + "description": "Label added successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { - "description": "Document or folder not found" + "description": "Document or label not found" } } - } - }, - "/api/v1/documents/{identifier}/permissions": { - "get": { - "operationId": "documentsGetPermissions", - "summary": "Get document permissions", + }, + "delete": { + "operationId": "documentsRemoveLabel", + "summary": "Remove label from document", "tags": [ "Documents" ], @@ -11965,36 +35069,40 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "name": "identifier", "in": "path" }, { "schema": { "type": "string", - "format": "uuid", - "description": "User membership ID to check permissions for" + "description": "Label name", + "example": "verified" }, "required": true, - "description": "User membership ID to check permissions for", + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", "name": "userId", "in": "query" } ], "responses": { - "200": { - "description": "User permissions for the document", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" - } - } - } + "204": { + "description": "Label removed successfully" }, "401": { "description": "Authentication required" @@ -12003,13 +35111,15 @@ "description": "Permission denied" }, "404": { - "description": "Document or user not found" + "description": "Document not found" } } - }, + } + }, + "/api/v1/documents/{identifier}/transfer-ownership": { "put": { - "operationId": "documentsUpdatePermissionSettings", - "summary": "Update document permission settings", + "operationId": "documentsTransferOwnership", + "summary": "Transfer document ownership", "tags": [ "Documents" ], @@ -12030,14 +35140,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" + "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" } } } }, "responses": { "200": { - "description": "Permission settings updated successfully", + "description": "Ownership transferred successfully", "content": { "application/json": { "schema": { @@ -12047,22 +35157,24 @@ } }, "400": { - "description": "Invalid request body" + "description": "Invalid user ID" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied - MANAGER role or owner required" }, "404": { - "description": "Document not found" + "description": "Document or user not found" } } - }, - "post": { - "operationId": "documentsAddPermits", - "summary": "Add document permits", + } + }, + "/api/v1/documents/{identifier}/access-list": { + "get": { + "operationId": "documentsAccessList", + "summary": "List document access principals", "tags": [ "Documents" ], @@ -12077,45 +35189,115 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction (default: asc)", + "example": "desc" + }, + "required": false, + "description": "Sort direction (default: asc)", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "direct", + "folder" + ], + "description": "Filter by access source: direct or folder" + }, + "required": false, + "description": "Filter by access source: direct or folder", + "name": "accessSource", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "user", + "userGroup" + ], + "description": "Filter by principal type: user or userGroup" + }, + "required": false, + "description": "Filter by principal type: user or userGroup", + "name": "type", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsAddPermitsBody" - } - } - } - }, "responses": { "200": { - "description": "Permissions added successfully", + "description": "List of users and groups with access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsAccessListResponse" } } } }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied - VIEWER role required" }, "404": { "description": "Document not found" } } - }, - "patch": { - "operationId": "documentsUpdatePermits", - "summary": "Update document permits", + } + }, + "/api/v1/documents/{identifier}/favorites": { + "get": { + "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", + "operationId": "documentsListFavorites", + "summary": "List users who favorited the document", "tags": [ "Documents" ], @@ -12130,45 +35312,127 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "example": "desc" + }, + "required": false, + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "name": "sortDirection", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of users who favorited the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsListFavoritesResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied — caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" + }, + "404": { + "description": "Document not found" } + } + } + }, + "/api/v2/documents": { + "post": { + "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to existing content).", + "operationId": "documentsV2Create", + "summary": "Create document", + "tags": [ + "Documents" ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" + "$ref": "#/components/schemas/DocumentsV2CreateBody" } } } }, "responses": { - "200": { - "description": "Permissions updated successfully", + "201": { + "description": "Document created and published successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsV2CreateResponse" } } } }, "400": { - "description": "Invalid request body - userIds or userGroupIds required" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Insufficient permissions to create a document on this model." }, "404": { - "description": "Document not found" + "description": "Base model or branch not found." + }, + "405": { + "description": "Method not allowed." } } - }, - "delete": { - "operationId": "documentsRevokePermits", - "summary": "Revoke document permits", + } + }, + "/api/v2/documents/{identifier}": { + "get": { + "description": "Read the document's current draft state (or the published state if no draft exists). Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2Get", + "summary": "Read document state", "tags": [ "Documents" ], @@ -12176,54 +35440,46 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsRevokePermitsBody" - } - } - } - }, "responses": { "200": { - "description": "Permissions revoked successfully", + "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsV2ReadResponse" } } } }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" - }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Insufficient permissions to read the document." }, "404": { - "description": "Document not found" + "description": "Document not found." + }, + "422": { + "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." } - } - } - }, - "/api/v1/documents/{identifier}/draft": { - "post": { - "operationId": "documentsCreateDraft", - "summary": "Create document draft", + } + } + }, + "/api/v2/documents/{identifier}/draft": { + "patch": { + "description": "Create a new draft on the published document and apply the patch. No auto-publish — the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", + "operationId": "documentsV2PatchDraft", + "summary": "Create draft and patch document", "tags": [ "Documents" ], @@ -12231,11 +35487,11 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" } @@ -12244,39 +35500,51 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftBody" + "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" } } } }, "responses": { "200": { - "description": "Draft created or existing draft returned", + "description": "Draft created and patch applied successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftResponse" + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" } } } }, "400": { - "description": "Document is not eligible for publishing workflow" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Insufficient permissions to update the document." }, "404": { - "description": "Document or branch not found" + "description": "Document or branch not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." } } - }, - "delete": { - "operationId": "documentsDiscardDraft", - "summary": "Discard document draft", + } + }, + "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { + "get": { + "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2GetDraft", + "summary": "Read draft state", "tags": [ "Documents" ], @@ -12284,51 +35552,55 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" + }, + "required": true, + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Published document identifier.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Published document identifier.", "name": "identifier", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftBody" - } - } - } - }, "responses": { "200": { - "description": "Draft discarded successfully", + "description": "Draft state.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" + "$ref": "#/components/schemas/DocumentsV2ReadResponse" } } } }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to read the draft." }, "404": { - "description": "Document or draft not found" + "description": "Document or draft not found." + }, + "422": { + "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." } } - } - }, - "/api/v1/documents/{identifier}/duplicate": { - "post": { - "operationId": "documentsDuplicate", - "summary": "Duplicate document", + }, + "patch": { + "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, no publish.", + "operationId": "documentsV2PatchDraftByIdentifier", + "summary": "Patch draft", "tags": [ "Documents" ], @@ -12336,65 +35608,75 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", "in": "path" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Published document identifier.", + "example": "abc123" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "description": "Published document identifier.", + "name": "identifier", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateBody" + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" } } } }, "responses": { - "201": { - "description": "Document duplicated successfully", + "200": { + "description": "Patch applied to draft successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateResponse" + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" } } } }, "400": { - "description": "Invalid name or folder path" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to update the draft." }, "404": { - "description": "Document or folder not found" + "description": "Document or draft not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." } } } }, - "/api/v1/documents/{identifier}/favorite": { - "put": { - "operationId": "documentsAddFavorite", - "summary": "Add document to favorites", + "/api/v2/documents/{identifier}/draft/publish": { + "post": { + "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body — the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", + "operationId": "documentsV2PublishDraft", + "summary": "Publish draft", "tags": [ "Documents" ], @@ -12402,479 +35684,565 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { - "204": { - "description": "Favorite added successfully" + "200": { + "description": "Draft published successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" + } + } + } + }, + "400": { + "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to publish the draft." }, "404": { - "description": "Document not found" + "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document." } } - }, - "delete": { - "operationId": "documentsRemoveFavorite", - "summary": "Remove document from favorites", + } + }, + "/api/v1/embed/sso/generate-session": { + "post": { + "operationId": "embedSsoGenerateSession", + "summary": "Generate embedded SSO session", "tags": [ - "Documents" + "Embed" ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" + } + } } - ], + }, "responses": { - "204": { - "description": "Favorite removed successfully" + "200": { + "description": "Session token generated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" }, "401": { - "description": "Authentication required" + "description": "Authentication required (API key with embed scope)" }, "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" + "description": "Permission denied - embed not enabled" } } } }, - "/api/v1/documents/{identifier}/labels": { - "patch": { - "operationId": "documentsBulkUpdateLabels", - "summary": "Bulk update document labels", + "/api/v1/ai/eval/prompt-sets": { + "get": { + "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", + "operationId": "aiEvalPromptSetsList", + "summary": "List eval prompt sets", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" + "enum": [ + "true", + "false" + ], + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "example": "false" }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" + "required": false, + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "name": "archived", + "in": "query" }, { "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." }, "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", + "name": "model_ids", "in": "query" } ], + "responses": { + "200": { + "description": "List of prompt sets, sorted alphabetically by name.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsListResponse" + } + } + } + }, + "400": { + "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "No eval-accessible models for this caller.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "post": { + "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", + "operationId": "aiEvalPromptSetsCreate", + "summary": "Create an eval prompt set", + "tags": [ + "AI Eval" + ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" + "$ref": "#/components/schemas/EvalPromptSetsCreateBody" } } } }, "responses": { - "200": { - "description": "Labels updated successfully", + "201": { + "description": "Prompt set created successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" + "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" } } } }, "400": { - "description": "Invalid request - at least one label must be specified" + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" + "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } } } } }, - "/api/v1/documents/{identifier}/labels/{labelName}": { - "put": { - "operationId": "documentsAddLabel", - "summary": "Add label to document", + "/api/v1/ai/eval/prompt-sets/{promptSetId}": { + "get": { + "description": "Get a single prompt set with all of its prompts.", + "operationId": "aiEvalPromptSetsGet", + "summary": "Get an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "required": true, - "description": "Document identifier", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Label name", - "name": "labelName", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { - "204": { - "description": "Label added successfully" + "200": { + "description": "Prompt set details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsGetResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document or label not found" + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } } } }, - "delete": { - "operationId": "documentsRemoveLabel", - "summary": "Remove label from document", + "patch": { + "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list — existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", + "operationId": "aiEvalPromptSetsUpdate", + "summary": "Update an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "required": true, - "description": "Document identifier", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "required": true, - "description": "Label name", - "name": "labelName", - "in": "path" - }, { "schema": { "type": "string", "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Label removed successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/transfer-ownership": { - "put": { - "operationId": "documentsTransferOwnership", - "summary": "Transfer document ownership", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" + "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" } } } }, "responses": { "200": { - "description": "Ownership transferred successfully", + "description": "Prompt set updated successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" } } } }, "400": { - "description": "Invalid user ID" + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role or owner required" - }, - "404": { - "description": "Document or user not found" - } - } - } - }, - "/api/v1/documents/{identifier}/access-list": { - "get": { - "operationId": "documentsAccessList", - "summary": "List document access principals", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "number", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction (default: asc)", - "example": "desc" - }, - "required": false, - "description": "Sort direction (default: asc)", - "name": "sortDirection", - "in": "query" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, - { - "schema": { - "type": "string", - "description": "Field to sort results by" - }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, - { - "schema": { - "type": "string", - "enum": [ - "direct", - "folder" - ], - "description": "Filter by access source: direct or folder" - }, - "required": false, - "description": "Filter by access source: direct or folder", - "name": "accessSource", - "in": "query" + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } }, + "422": { + "description": "A `prompts[].id` in the request does not belong to this prompt set.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + } + } + }, + "delete": { + "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent — retrying drains any remaining runs.", + "operationId": "aiEvalPromptSetsArchive", + "summary": "Archive an eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ { "schema": { "type": "string", - "enum": [ - "user", - "userGroup" - ], - "description": "Filter by principal type: user or userGroup" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Filter by principal type: user or userGroup", - "name": "type", - "in": "query" + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" } ], "responses": { "200": { - "description": "List of users and groups with access", + "description": "Prompt set archived successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsAccessListResponse" + "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" } } } }, "401": { - "description": "Authentication required" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied - VIEWER role required" + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document not found" + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "500": { + "description": "Archive committed but a run-cancellation failed; the set is already archived — safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } } } } }, - "/api/v1/embed/sso/generate-session": { + "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { "post": { - "operationId": "embedSsoGenerateSession", - "summary": "Generate embedded SSO session", + "description": "Restore an archived prompt set.", + "operationId": "aiEvalPromptSetsUnarchive", + "summary": "Restore an archived eval prompt set", "tags": [ - "Embed" + "AI Eval" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" - } - } + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" } - }, + ], "responses": { "200": { - "description": "Session token generated", + "description": "Prompt set restored successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" + "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" } } } }, "400": { - "description": "Invalid request body" + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required (API key with embed scope)" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied - embed not enabled" + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } } } } @@ -13437,6 +36805,7 @@ { "schema": { "type": "string", + "format": "uuid", "description": "Target user membership ID (for org-scoped API keys)" }, "required": false, @@ -13540,6 +36909,7 @@ { "schema": { "type": "string", + "format": "uuid", "description": "Target user membership ID (for org-scoped API keys)" }, "required": false, @@ -13606,6 +36976,7 @@ { "schema": { "type": "string", + "format": "uuid", "description": "Target user membership ID (for org-scoped API keys)" }, "required": false, @@ -14811,6 +38182,43 @@ "description": "Branch ID for branch-based schema refresh. Required when branch-based schema refresh is enabled for the connection. Must not be provided when branch-based schema refresh is not enabled.", "name": "branch_id", "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", + "example": "false" + }, + "required": false, + "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", + "name": "hard_refresh", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "example": "public,analytics" + }, + "required": false, + "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "name": "schemas", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "example": "public.orders,public.customers" + }, + "required": false, + "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "name": "tables", + "in": "query" } ], "responses": { @@ -14825,7 +38233,7 @@ } }, "400": { - "description": "Bad request - branch_id required when branch-based schema refresh is enabled, or branch_id not allowed when it is not enabled" + "description": "Bad request - branch_id required when branch-based schema refresh is enabled, branch_id not allowed when it is not enabled, or hard refresh requested with selective schemas/tables filters" }, "401": { "description": "Authentication required" @@ -15050,15 +38458,15 @@ }, { "schema": { - "type": "number", + "type": "integer", "minimum": 1, "maximum": 100, "default": 20, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "example": 20 }, "required": false, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "name": "pageSize", "in": "query" }, @@ -15688,6 +39096,17 @@ "name": "content_filter_mode", "in": "query" }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter to documents created by this user (user ID). Unknown IDs return 400." + }, + "required": false, + "description": "Filter to documents created by this user (user ID). Unknown IDs return 400.", + "name": "creator_id", + "in": "query" + }, { "schema": { "type": "string", @@ -15805,6 +39224,7 @@ { "schema": { "type": "string", + "format": "uuid", "description": "Target user membership ID (for org-scoped API keys)" }, "required": false, @@ -15897,7 +39317,7 @@ "extension", "staged", "merged", - "history" + "fully-resolved" ], "default": "combined", "description": "IDE mode for YAML operations" @@ -16084,7 +39504,7 @@ "extension", "staged", "merged", - "history" + "fully-resolved" ], "default": "combined", "description": "IDE mode for YAML operations" @@ -16124,6 +39544,51 @@ } } }, + "/api/v1/models/{modelId}/ai-agent-actions": { + "get": { + "description": "Returns the AI agent actions configured for this model — a unified list of sample queries and skills suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is ready to submit verbatim to `POST /api/v1/ai/jobs`.", + "operationId": "modelAiAgentActions", + "summary": "Get model AI agent actions", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "AI agent actions in display order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentActionsResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key." + }, + "403": { + "description": "Caller cannot read the model." + }, + "404": { + "description": "Model not found." + } + } + } + }, "/api/v1/query/run": { "post": { "operationId": "queryRun", @@ -16131,6 +39596,19 @@ "tags": [ "Query" ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], "requestBody": { "content": { "application/json": { @@ -16248,15 +39726,15 @@ }, { "schema": { - "type": "number", + "type": "integer", "minimum": 1, "maximum": 100, "default": 20, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "example": 20 }, "required": false, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "name": "pageSize", "in": "query" }, @@ -17118,7 +40596,7 @@ "description": "Schedule not found" }, "409": { - "description": "Another execution is in progress for this schedule" + "description": "Schedule cannot be triggered (paused, system-disabled, or another execution is in progress)" } } } @@ -18026,15 +41504,15 @@ }, { "schema": { - "type": "number", + "type": "integer", "minimum": 1, "maximum": 100, "default": 20, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "example": 20 }, "required": false, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "name": "pageSize", "in": "query" }, diff --git a/cmd/omni/agent_help.go b/cmd/omni/agent_help.go index 327abc9..3b42409 100644 --- a/cmd/omni/agent_help.go +++ b/cmd/omni/agent_help.go @@ -38,11 +38,29 @@ Set OMNI_API_TOKEN env var, or run: omni config init ### Download a dashboard omni dashboards download +### Read or edit a document (v2) + # Read live state. The response is a valid draft PATCH body (round-trip design). + omni documents v2-get --compact + + # Edit metadata with flags (no JSON needed), then publish the draft: + omni documents v2-patch-draft --name "Q3 Revenue" --summary "rename" + omni documents v2-publish-draft + + # Edit content by round-tripping the full state through a file: + omni documents v2-get > doc.json + # ...edit doc.json (containers, controls, queryPresentations, settings)... + omni documents v2-patch-draft --body - < doc.json + omni documents v2-publish-draft + + # Create a brand-new document (published immediately): + omni documents v2-create "My Dashboard" + ### Search Omni documentation omni ai search-omni-docs --body '{"query":"how do I..."}' ## Command Groups ai AI-powered query generation, jobs, doc search + ai-eval AI eval prompt set management connections Manage database connections content List content across the org dashboards Download dashboards, manage filters diff --git a/cmd/omni/openapi.json b/cmd/omni/openapi.json index b83fb7c..8697147 100644 --- a/cmd/omni/openapi.json +++ b/cmd/omni/openapi.json @@ -15,6 +15,10 @@ "description": "AI-powered data analysis. Submit natural language questions as synchronous queries or asynchronous jobs, and retrieve results including generated queries, data, and summarized answers.", "name": "AI" }, + { + "description": "AI evaluation: manage prompt sets and runs used to score AI quality against curated prompt suites.", + "name": "AI Eval" + }, { "description": "API token management", "name": "API Tokens" @@ -118,407 +122,559 @@ "description": "Update an existing variable by ID. Variable names cannot be changed after creation.", "title": "DbtEnvironmentVariableUpdate" }, - "AiGenerateQueryResponse": { + "CompositeFilter": { "type": "object", "properties": { - "error": { - "type": [ - "object", - "null" - ], - "properties": { - "detail": { - "type": "string", - "description": "Detailed error message explaining why query generation failed.", - "example": "The AI was unable to generate a query for this prompt. Try rephrasing your question to be more specific about the data you want to retrieve." - }, - "message": { - "type": "string", - "description": "Short error summary.", - "example": "No query generated" - } - }, - "required": [ - "detail", - "message" - ], - "description": "Error details if query generation failed. Null on success." - }, - "query": { - "$ref": "#/components/schemas/AiSemanticQuery" - }, - "result": { - "type": "object", - "additionalProperties": {}, - "description": "Query execution results as a JSON object. Only present when runQuery is true (the default) and the query executed successfully. The structure contains the query result data." + "cancel_query_filter": { + "type": "boolean" }, - "topic": { - "type": "string", - "description": "The topic name that was used for query generation.", - "example": "order_items" + "ignore_if_unjoinable": { + "type": "boolean" }, - "workbookUrl": { + "conjunction": { "type": "string", - "format": "uri", - "description": "URL to view and edit the generated query in an Omni workbook. Only present when workbookUrl was set to true in the request.", - "example": "https://myorg.omni.co/w/abc123/1" - } - }, - "required": [ - "error", - "query" - ] - }, - "AiSemanticQuery": { - "type": [ - "object", - "null" - ], - "properties": { - "fields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Ordered list of fully qualified field names to include in the query (e.g., \"view_name.field_name\").", - "example": [ - "products.name", - "order_items.total_revenue" + "enum": [ + "OR", + "AND" ] }, "filters": { - "type": "object", - "additionalProperties": {}, - "description": "Filter conditions keyed by fully qualified field name. Filter values vary by field type." - }, - "limit": { - "type": "integer", - "description": "Maximum number of rows to return.", - "example": 500 - }, - "sorts": { "type": "array", "items": { - "$ref": "#/components/schemas/AiQuerySort" - }, - "description": "Sort specifications applied to the query results." - }, - "table": { - "type": "string", - "description": "The base topic or view name for the query.", - "example": "order_items" - } - }, - "required": [ - "fields" - ], - "additionalProperties": {}, - "description": "The generated semantic query definition. Null if generation failed. This query can be passed directly to the POST /api/v1/query/run endpoint." - }, - "AiQuerySort": { - "type": "object", - "properties": { - "column_name": { - "type": "string", - "description": "Fully qualified field name to sort by (e.g., \"view_name.field_name\").", - "example": "order_items.total_revenue" - }, - "sort_descending": { - "type": "boolean", - "description": "Whether to sort in descending order.", - "example": true - } - }, - "required": [ - "column_name", - "sort_descending" - ] - }, - "ApiError400": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Bad Request: prompt: Required" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 400 - } - }, - "required": [ - "detail", - "status" - ] - }, - "ApiError401": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Unauthorized: Missing or invalid API key" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 401 - } - }, - "required": [ - "detail", - "status" - ] - }, - "ApiError403": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Forbidden: AI query generation is not enabled for this organization" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 403 - } - }, - "required": [ - "detail", - "status" - ] - }, - "ApiError404": { - "type": "object", - "properties": { - "detail": { - "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "Model 770e8400-e29b-41d4-a716-446655440002 not found" - }, - "status": { - "type": "integer", - "description": "HTTP status code of the error.", - "example": 404 - } - }, - "required": [ - "detail", - "status" - ] - }, - "AiGenerateQueryBody": { - "allOf": [ - { - "$ref": "#/components/schemas/AiTopicParams" - }, - { - "type": "object", - "properties": { - "prompt": { - "type": "string", - "description": "The natural language prompt describing the data you want to retrieve.", - "example": "Show me total revenue by month for the last year" - }, - "queryAllViews": { - "type": "boolean", - "description": "If true and the model has query_all_views_and_fields enabled, AI can query views not in any topic." - }, - "runQuery": { - "type": "boolean", - "description": "Whether to execute the generated query and return results. Defaults to true. Set to false to only generate the query definition without executing it.", - "example": true - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID to execute the query as. Their permissions will be applied for row-level security. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", - "example": "990e8400-e29b-41d4-a716-446655440004" - }, - "workbookUrl": { - "type": "boolean", - "description": "If true, creates a new workbook with the generated query and returns its URL. Useful for sharing results or further exploration.", - "example": false - } - }, - "required": [ - "prompt" - ] - } - ] - }, - "AiTopicParams": { - "type": "object", - "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "currentTopicName": { - "type": "string", - "description": "The name of the current topic to scope query generation. If not provided, AI will automatically select the best topic for your prompt.", - "example": "order_items" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the shared model to query against. Only shared models are supported.", - "example": "770e8400-e29b-41d4-a716-446655440002" - } - }, - "required": [ - "modelId" - ] - }, - "AiPickTopicResponse": { - "type": "object", - "properties": { - "topicId": { - "type": "string", - "description": "The name of the topic that best matches the prompt. Use this as the topicName parameter when calling generate-query or submitting an AI job.", - "example": "order_items" + "anyOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + } + }, + "required": [ + "kind", + "type", + "values" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + } + }, + "required": [ + "kind", + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + } + }, + "required": [ + "type", + "user_attribute_name" + ] + }, + { + "$ref": "#/components/schemas/CompositeFilter" + } + ] + }, + "description": "Child filters — each a simple filter or another composite filter. Recursive; see the dashboard-filters reference for the full grammar." + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] } }, "required": [ - "topicId" + "conjunction", + "filters", + "type" ] }, - "AiPickTopicBody": { - "allOf": [ - { - "$ref": "#/components/schemas/AiTopicParams" - }, - { - "type": "object", - "properties": { - "potentialTopicNames": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional list of topic names to limit consideration to. If not provided, all topics the user has access to in the model will be evaluated.", - "example": [ - "order_items", - "customers", - "products" - ] - }, - "prompt": { + "AiGenerateQueryResponse": { + "type": "object", + "properties": { + "baseView": { + "type": [ + "string", + "null" + ], + "description": "The base view name used for query generation when queryAllViews surfaced a non-topic view. Mutually exclusive with `topic` — exactly one is non-null when a query was generated.", + "example": null + }, + "downgradedModelTier": { + "type": "string", + "description": "Present only when the organization is over its AI downgrade threshold, signaling the query was generated on a downgraded (cheaper) model tier (e.g. 'haiku') to conserve credits. Advisory and best-effort — the call still succeeds, and clients may surface that a downgraded model was used. Absent when no downgrade applied.", + "example": "haiku" + }, + "error": { + "type": [ + "object", + "null" + ], + "properties": { + "detail": { "type": "string", - "description": "The natural language prompt to analyze. The AI will determine which topic best matches the data described in this prompt.", - "example": "How many orders were placed last month?" + "description": "Detailed error message explaining why query generation failed.", + "example": "The AI was unable to generate a query for this prompt. Try rephrasing your question to be more specific about the data you want to retrieve." }, - "userId": { + "message": { "type": "string", - "format": "uuid", - "description": "User ID to evaluate topic access as. Their permissions will be used for permission-aware topic selection. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", - "example": "990e8400-e29b-41d4-a716-446655440004" + "description": "Short error summary.", + "example": "No query generated" } }, "required": [ - "prompt" - ] + "detail", + "message" + ], + "description": "Error details if query generation failed. Null on success." + }, + "query": { + "$ref": "#/components/schemas/AiSemanticQuery" + }, + "result": { + "type": "object", + "additionalProperties": {}, + "description": "Query execution results as a JSON object. Only present when runQuery is true (the default) and the query executed successfully. The structure contains the query result data." + }, + "topic": { + "type": [ + "string", + "null" + ], + "description": "The topic name used for query generation. Mutually exclusive with `baseView` — exactly one is non-null when a query was generated.", + "example": "order_items" + }, + "workbookUrl": { + "type": "string", + "format": "uri", + "description": "URL to view and edit the generated query in an Omni workbook. Only present when workbookUrl was set to true in the request.", + "example": "https://myorg.omni.co/w/abc123/1" } + }, + "required": [ + "error", + "query" ] }, - "AiSearchOmniDocsResponse": { - "type": "object", + "AiSemanticQuery": { + "type": [ + "object", + "null" + ], "properties": { - "answer": { - "type": "string", - "description": "A synthesized answer to the question, based on the Omni documentation.", - "example": "To create a dashboard filter, navigate to your dashboard and click the \"Add Filter\" button..." + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of fully qualified field names to include in the query (e.g., \"view_name.field_name\").", + "example": [ + "products.name", + "order_items.total_revenue" + ] }, - "sources": { + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filter conditions keyed by fully qualified field name. Filter values vary by field type." + }, + "limit": { + "type": "integer", + "description": "Maximum number of rows to return.", + "example": 500 + }, + "sorts": { "type": "array", "items": { - "type": "object", - "properties": { - "title": { - "type": "string", - "description": "The title of the source documentation page.", - "example": "Dashboard Filters" - }, - "url": { - "type": "string", - "format": "uri", - "description": "URL of the source documentation page.", - "example": "https://docs.omni.co/docs/dashboards/filters" - } - }, - "required": [ - "title", - "url" - ] + "$ref": "#/components/schemas/AiQuerySort" }, - "description": "List of documentation pages that were used to synthesize the answer." + "description": "Sort specifications applied to the query results." + }, + "table": { + "type": "string", + "description": "The base topic or view name for the query.", + "example": "order_items" } }, "required": [ - "answer", - "sources" - ] + "fields" + ], + "additionalProperties": {}, + "description": "The generated semantic query definition. Null if generation failed. This query can be passed directly to the POST /api/v1/query/run endpoint." }, - "AiSearchOmniDocsBody": { + "AiQuerySort": { "type": "object", "properties": { - "question": { + "column_name": { "type": "string", - "minLength": 1, - "maxLength": 2000, - "description": "A natural language question about Omni features, configuration, modeling, dashboards, or other topics covered in the Omni documentation.", - "example": "How do I create a dashboard filter?" + "description": "Fully qualified field name to sort by (e.g., \"view_name.field_name\").", + "example": "order_items.total_revenue" + }, + "sort_descending": { + "type": "boolean", + "description": "Whether to sort in descending order.", + "example": true } }, "required": [ - "question" + "column_name", + "sort_descending" ] }, - "AiJobSubmitResponse": { + "ApiError400": { "type": "object", "properties": { - "conversationId": { - "type": "string", - "format": "uuid", - "description": "The conversation ID for this job. Pass this as conversationId in subsequent job submissions to continue the conversation with additional context.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "jobId": { + "detail": { "type": "string", - "format": "uuid", - "description": "The unique identifier for the created job. Use this to poll status via GET /api/v1/ai/jobs/{jobId} or retrieve results via GET /api/v1/ai/jobs/{jobId}/result.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Human-readable error message describing what went wrong.", + "example": "Bad Request: prompt: Required" }, - "omniChatUrl": { - "type": "string", - "format": "uri", - "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", - "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 400 } }, "required": [ - "conversationId", - "jobId", - "omniChatUrl" + "detail", + "status" ] }, - "ApiError409": { + "ApiError401": { "type": "object", "properties": { "detail": { "type": "string", "description": "Human-readable error message describing what went wrong.", - "example": "An active job already exists for this conversation" + "example": "Unauthorized: Missing or invalid API key" }, "status": { "type": "integer", "description": "HTTP status code of the error.", - "example": 409 + "example": 401 } }, "required": [ @@ -526,845 +682,1021 @@ "status" ] }, - "AiJobSubmitBody": { + "AiCreditShutoffError": { "type": "object", "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Use this to query against in-progress model changes.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "conversationId": { - "type": "string", - "format": "uuid", - "description": "Conversation ID to continue an existing conversation thread. The AI will have access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. Only one active job can exist per conversation.", - "example": "660e8400-e29b-41d4-a716-446655440001" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the shared model to query against. Only shared models are supported.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "progressWebhookEnabled": { - "type": "boolean", - "default": false, - "description": "When true, real-time progress events are POSTed to webhookUrl during execution (e.g., \"Searching for revenue fields\", \"Query returned 42 rows\"). Requires webhookUrl. Progress events are best-effort: single attempt, no retries, failures do not affect job execution.", - "example": true - }, - "prompt": { - "type": "string", - "minLength": 1, - "description": "The natural language prompt for the AI to process. The AI will analyze your question, generate appropriate queries, execute them, and return a summarized answer.", - "example": "What are the top 5 products by revenue this quarter?" - }, - "topicName": { + "code": { "type": "string", - "maxLength": 256, - "description": "Topic name to scope query generation. Topics define a set of related views and their join paths. If not provided, the AI will automatically select the best topic. Use the pick-topic endpoint to determine the right topic programmatically.", - "example": "order_items" - }, - "webhookMetadata": { - "type": "object", - "additionalProperties": {}, - "description": "Arbitrary metadata object that will be included unchanged in webhook payloads. Use this to correlate webhook notifications with your own system (e.g., tracking IDs, channel references).", - "example": { - "externalId": "task-123", - "slackChannel": "C0123456789" - } + "enum": [ + "shutoff" + ], + "description": "Stable reason code identifying an AI-credit shutoff.", + "example": "shutoff" }, - "webhookSigningSecret": { + "detail": { "type": "string", - "description": "Secret key for HMAC-SHA256 webhook payload signing. When provided, each webhook request includes X-Omni-Signature and X-Omni-Signature-Timestamp headers for verification. Required if webhookUrl is specified." + "description": "Human-readable error message describing what went wrong.", + "example": "The AI agent is currently unavailable. Contact your administrator to re-enable." }, - "webhookUrl": { - "type": "string", - "format": "uri", - "description": "URL to receive webhook POSTs. Always receives a terminal event (job.complete or job.failed) when the job finishes. When progressWebhookEnabled is true, also receives real-time progress events during execution.", - "example": "https://example.com/webhooks/omni" + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 402 } }, "required": [ - "modelId", - "prompt" + "code", + "detail", + "status" ] }, - "AiJobStatusResponse": { + "ApiError403": { "type": "object", "properties": { - "branchId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Branch ID used for model context, or null if querying the main shared model." - }, - "cancelledAt": { - "type": "string", - "format": "date-time", - "description": "When the job was cancelled. Only present in CANCELLED state.", - "example": "2025-01-15T10:00:12.000Z" - }, - "cancelledBy": { - "type": "string", - "format": "uuid", - "description": "User ID of who cancelled the job. Only present in CANCELLED state.", - "example": "990e8400-e29b-41d4-a716-446655440004" - }, - "completedAt": { + "detail": { "type": "string", - "format": "date-time", - "description": "When the job finished (successfully or with error). Present in COMPLETE and FAILED states.", - "example": "2025-01-15T10:01:30.000Z" + "description": "Human-readable error message describing what went wrong.", + "example": "Forbidden: AI query generation is not enabled for this organization" }, - "conversationId": { + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 403 + } + }, + "required": [ + "detail", + "status" + ] + }, + "ApiError404": { + "type": "object", + "properties": { + "detail": { "type": "string", - "format": "uuid", - "description": "The conversation this job belongs to. Use this to submit follow-up jobs in the same conversation thread.", - "example": "660e8400-e29b-41d4-a716-446655440001" + "description": "Human-readable error message describing what went wrong.", + "example": "Model 770e8400-e29b-41d4-a716-446655440002 not found" }, - "createdAt": { - "type": "string", - "format": "date-time", - "description": "When the job was submitted.", - "example": "2025-01-15T10:00:00.000Z" + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 404 + } + }, + "required": [ + "detail", + "status" + ] + }, + "AiGenerateQueryBody": { + "allOf": [ + { + "$ref": "#/components/schemas/AiTopicParams" }, - "error": { + { "type": "object", "properties": { - "code": { + "prompt": { "type": "string", - "description": "Machine-readable error code.", - "example": "QUERY_EXECUTION_ERROR" + "description": "The natural language prompt describing the data you want to retrieve.", + "example": "Show me total revenue by month for the last year" }, - "detail": { - "type": "string", - "description": "Additional error detail or context.", - "example": "The query timed out after 300 seconds" + "queryAllViews": { + "type": "boolean", + "description": "If true and the model has query_all_views_and_fields enabled, AI can query views not in any topic." }, - "message": { - "type": "string", - "description": "Human-readable error message.", - "example": "Column 'revenue' not found in table 'orders'" - } - }, - "required": [ - "message" - ], - "additionalProperties": {}, - "description": "Error details explaining why the job failed. Only present in FAILED state." - }, - "executionStartedAt": { - "type": "string", - "format": "date-time", - "description": "When execution began. Present once the job transitions from QUEUED to EXECUTING. May be absent on jobs that failed or were cancelled before execution started.", - "example": "2025-01-15T10:00:05.000Z" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "The unique identifier for this job.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "modelId": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "The shared model ID used for query generation.", - "example": "770e8400-e29b-41d4-a716-446655440002" - }, - "omniChatUrl": { - "type": "string", - "format": "uri", - "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", - "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" - }, - "organizationId": { - "type": "string", - "format": "uuid", - "description": "The organization that owns this job.", - "example": "880e8400-e29b-41d4-a716-446655440003" - }, - "progress": { - "type": [ - "object", - "null" - ], - "properties": { - "iteration": { - "type": "integer", - "description": "Current iteration number. The AI may take multiple iterations to refine queries and generate a complete answer.", - "example": 2 + "runQuery": { + "type": "boolean", + "description": "Whether to execute the generated query and return results. Defaults to true. Set to false to only generate the query definition without executing it.", + "example": true }, - "message": { + "userId": { "type": "string", - "description": "Human-readable status message describing what the AI is currently doing.", - "example": "Running query: Top products by revenue" + "format": "uuid", + "description": "User ID to execute the query as. Their permissions will be applied for row-level security. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", + "example": "990e8400-e29b-41d4-a716-446655440004" }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "When this progress update was recorded.", - "example": "2025-01-15T10:00:08.000Z" + "workbookUrl": { + "type": "boolean", + "description": "If true, creates a new workbook with the generated query and returns its URL. Useful for sharing results or further exploration.", + "example": false } }, "required": [ - "iteration", - "message", - "updatedAt" - ], - "description": "Real-time progress information. Only present in EXECUTING state. Null if no progress has been reported yet. Updated in real-time as the AI works through iterations." - }, - "prompt": { - "type": "string", - "description": "The natural language prompt that was submitted.", - "example": "What are the top 5 products by revenue?" - }, - "resultSummary": { + "prompt" + ] + } + ] + }, + "AiTopicParams": { + "type": "object", + "properties": { + "branchId": { "type": "string", - "description": "Markdown-formatted summary of the job result. Only present in COMPLETE state. For the full result with query details and data, use GET /api/v1/ai/jobs/{jobId}/result.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "state": { + "currentTopicName": { "type": "string", - "enum": [ - "CANCELLED", - "COMPLETE", - "DELIVERING", - "EXECUTING", - "FAILED", - "QUEUED" - ], - "description": "Current state of the job. Terminal states are COMPLETE, FAILED, and CANCELLED. Poll until the job reaches a terminal state.", - "example": "QUEUED" - }, - "topicName": { - "type": [ - "string", - "null" - ], - "description": "Topic name used to scope query generation, or null if the AI selected the topic automatically.", + "description": "The name of the current topic to scope query generation. If not provided, AI will automatically select the best topic for your prompt.", "example": "order_items" }, - "updatedAt": { - "type": "string", - "format": "date-time", - "description": "When the job record was last modified.", - "example": "2025-01-15T10:00:05.000Z" - }, - "userId": { + "modelId": { "type": "string", "format": "uuid", - "description": "The user ID who created (or is associated with) this job.", - "example": "990e8400-e29b-41d4-a716-446655440004" + "description": "The UUID of the shared model to query against. Only shared models are supported.", + "example": "770e8400-e29b-41d4-a716-446655440002" } }, "required": [ - "branchId", - "conversationId", - "createdAt", - "id", - "modelId", - "omniChatUrl", - "organizationId", - "prompt", - "state", - "topicName", - "updatedAt", - "userId" + "modelId" ] }, - "AiJobCancelResponse": { + "AiPickTopicResponse": { "type": "object", "properties": { - "jobId": { - "type": "string", - "format": "uuid", - "description": "The job ID that was requested to cancel.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "state": { + "topicId": { "type": "string", - "enum": [ - "CANCELLED", - "COMPLETE", - "DELIVERING", - "EXECUTING", - "FAILED", - "QUEUED" - ], - "description": "The job state after the cancellation attempt. CANCELLED if the cancellation was successful. If the job was already in a terminal state (COMPLETE, FAILED, CANCELLED), the current state is returned unchanged — the endpoint is idempotent.", - "example": "CANCELLED" + "description": "The name of the topic that best matches the prompt. Use this as the topicName parameter when calling generate-query or submitting an AI job.", + "example": "order_items" } }, "required": [ - "jobId", - "state" + "topicId" ] }, - "AiJobResultResponse": { - "type": "object", - "properties": { - "actions": { - "type": "array", + "AiPickTopicBody": { + "allOf": [ + { + "$ref": "#/components/schemas/AiTopicParams" + }, + { + "type": "object", + "properties": { + "potentialTopicNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional list of topic names to limit consideration to. If not provided, all topics the user has access to in the model will be evaluated.", + "example": [ + "order_items", + "customers", + "products" + ] + }, + "prompt": { + "type": "string", + "description": "The natural language prompt to analyze. The AI will determine which topic best matches the data described in this prompt.", + "example": "How many orders were placed last month?" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to evaluate topic access as. Their permissions will be used for permission-aware topic selection. Only valid with organization-scoped API keys. Personal access tokens always act as the authenticated user.", + "example": "990e8400-e29b-41d4-a716-446655440004" + } + }, + "required": [ + "prompt" + ] + } + ] + }, + "AiSearchOmniDocsResponse": { + "type": "object", + "properties": { + "answer": { + "type": "string", + "description": "A synthesized answer to the question, based on the Omni documentation.", + "example": "To create a dashboard filter, navigate to your dashboard and click the \"Add Filter\" button..." + }, + "sources": { + "type": "array", "items": { - "$ref": "#/components/schemas/AiJobAction" + "type": "object", + "properties": { + "title": { + "type": "string", + "description": "The title of the source documentation page.", + "example": "Dashboard Filters" + }, + "url": { + "type": "string", + "format": "uri", + "description": "URL of the source documentation page.", + "example": "https://docs.omni.co/docs/dashboards/filters" + } + }, + "required": [ + "title", + "url" + ] }, - "description": "Ordered list of actions the AI took during execution. Each action represents a step such as generating a query, executing it, or synthesizing a final answer." + "description": "List of documentation pages that were used to synthesize the answer." + } + }, + "required": [ + "answer", + "sources" + ] + }, + "AiSearchOmniDocsBody": { + "type": "object", + "properties": { + "question": { + "type": "string", + "minLength": 1, + "maxLength": 2000, + "description": "A natural language question about Omni features, configuration, modeling, dashboards, or other topics covered in the Omni documentation.", + "example": "How do I create a dashboard filter?" + } + }, + "required": [ + "question" + ] + }, + "AiJobSubmitResponse": { + "type": "object", + "properties": { + "conversationId": { + "type": "string", + "format": "uuid", + "description": "The conversation ID for this job. Pass this as conversationId in subsequent job submissions to continue the conversation with additional context.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "message": { + "jobId": { "type": "string", - "description": "The AI's final response message in Markdown format. This is the complete answer to the original prompt, incorporating data from all executed queries.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + "format": "uuid", + "description": "The unique identifier for the created job. Use this to poll status via GET /api/v1/ai/jobs/{jobId} or retrieve results via GET /api/v1/ai/jobs/{jobId}/result.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "omniChatUrl": { "type": "string", "format": "uri", "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" - }, - "resultSummary": { - "type": "string", - "description": "Summary of the job result. Typically matches the final message content.", - "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" - }, - "topic": { - "type": "string", - "description": "The topic name used for query generation.", - "example": "order_items" } }, - "additionalProperties": {} + "required": [ + "conversationId", + "jobId", + "omniChatUrl" + ] }, - "AiJobAction": { + "ApiError409": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "The AI's explanation of what it is doing in this step, written in natural language.", - "example": "I'll generate a query to find the top 5 products by total revenue." - }, - "result": { - "$ref": "#/components/schemas/AiJobActionQueryResult" - }, - "timestamp": { + "detail": { "type": "string", - "description": "ISO 8601 timestamp when this action occurred.", - "example": "2025-01-15T10:00:10.000Z" + "description": "Human-readable error message describing what went wrong.", + "example": "An active job already exists for this conversation" }, - "type": { - "type": "string", - "description": "The type of action. Common types include \"generate_query\" (query generation and execution) and \"summarize\" (final answer synthesis).", - "example": "generate_query" + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 409 } }, "required": [ - "message", - "timestamp", - "type" - ], - "additionalProperties": {} + "detail", + "status" + ] }, - "AiJobActionQueryResult": { + "AiJobSubmitBody": { "type": "object", "properties": { - "csvResult": { + "branchId": { "type": "string", - "description": "Query results formatted as CSV text.", - "example": "Name,Total Revenue\nRay-Ban Sunglasses,\"678,994.41\"\nLevi's 501 Jeans,\"475,072.00\"" + "format": "uuid", + "description": "Optional branch ID for the model. Must be a branch of the shared model specified by modelId. Use this to query against in-progress model changes.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "csvResultWasTruncated": { - "type": "boolean", - "description": "Whether the CSV data was truncated due to size limits. If true, the full result set may contain additional rows not included in csvResult.", - "example": false + "conversationId": { + "type": "string", + "format": "uuid", + "description": "Conversation ID to continue an existing conversation thread. The AI will have access to the context from previous jobs in the same conversation. If omitted, a new conversation is created. Only one active job can exist per conversation.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "hasResults": { + "modelId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the shared model to query against. Only shared models are supported.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "progressWebhookEnabled": { "type": "boolean", - "description": "Whether the query returned any data rows.", + "default": false, + "description": "When true, real-time progress events are POSTed to webhookUrl during execution (e.g., \"Searching for revenue fields\", \"Query returned 42 rows\"). Requires webhookUrl. Progress events are best-effort: single attempt, no retries, failures do not affect job execution.", "example": true }, - "query": { - "type": "object", - "additionalProperties": {}, - "description": "The semantic query definition that was executed. This can be used with the POST /api/v1/query/run endpoint to re-run the query." + "prompt": { + "type": "string", + "minLength": 1, + "description": "The natural language prompt for the AI to process. The AI will analyze your question, generate appropriate queries, execute them, and return a summarized answer.", + "example": "What are the top 5 products by revenue this quarter?" }, - "queryName": { + "topicName": { "type": "string", - "description": "Human-readable name describing what this query retrieves.", - "example": "Top 5 Products by Revenue" + "maxLength": 256, + "description": "Topic name to scope query generation. Topics define a set of related views and their join paths. If not provided, the AI will automatically select the best topic. Use the pick-topic endpoint to determine the right topic programmatically.", + "example": "order_items" }, - "status": { + "webhookMetadata": { + "type": "object", + "additionalProperties": {}, + "description": "Arbitrary metadata object that will be included unchanged in webhook payloads. Use this to correlate webhook notifications with your own system (e.g., tracking IDs, channel references).", + "example": { + "externalId": "task-123", + "slackChannel": "C0123456789" + } + }, + "webhookSigningSecret": { "type": "string", - "enum": [ - "success", - "error" - ], - "description": "Whether the query executed successfully.", - "example": "success" + "description": "Secret key for HMAC-SHA256 webhook payload signing. When provided, each webhook request includes X-Omni-Signature and X-Omni-Signature-Timestamp headers for verification. Required if webhookUrl is specified." }, - "totalRowCount": { - "type": "integer", - "description": "Total number of rows returned by the query.", - "example": 5 - } - }, - "required": [ - "csvResult", - "csvResultWasTruncated", - "hasResults", - "query", - "queryName", - "status", - "totalRowCount" - ], - "description": "Query result data. Only present for generate_query action types." - }, - "ApiError422": { - "type": "object", - "properties": { - "error": { + "webhookUrl": { "type": "string", - "description": "Human-readable error message describing what went wrong.", - "example": "No Arrow IPC data available for visualization" + "format": "uri", + "description": "URL to receive webhook POSTs. Always receives a terminal event (job.complete or job.failed) when the job finishes. When progressWebhookEnabled is true, also receives real-time progress events during execution.", + "example": "https://example.com/webhooks/omni" } }, "required": [ - "error" + "modelId", + "prompt" ] }, - "ApiKeyListResponse": { + "AiJobStatusResponse": { "type": "object", "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ApiKey" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "PageInfo": { - "type": "object", - "properties": { - "hasNextPage": { - "type": "boolean", - "description": "Whether more results are available" - }, - "nextCursor": { + "branchId": { "type": [ "string", "null" ], - "description": "Cursor for fetching the next page" + "format": "uuid", + "description": "Branch ID used for model context, or null if querying the main shared model." }, - "pageSize": { - "type": "number", - "description": "Number of results per page" + "cancelledAt": { + "type": "string", + "format": "date-time", + "description": "When the job was cancelled. Only present in CANCELLED state.", + "example": "2025-01-15T10:00:12.000Z" + }, + "cancelledBy": { + "type": "string", + "format": "uuid", + "description": "User ID of who cancelled the job. Only present in CANCELLED state.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "completedAt": { + "type": "string", + "format": "date-time", + "description": "When the job finished (successfully or with error). Present in COMPLETE and FAILED states.", + "example": "2025-01-15T10:01:30.000Z" + }, + "conversationId": { + "type": "string", + "format": "uuid", + "description": "The conversation this job belongs to. Use this to submit follow-up jobs in the same conversation thread.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "totalRecords": { - "type": "number", - "description": "Total number of records matching the query" - } - }, - "required": [ - "hasNextPage", - "nextCursor", - "pageSize", - "totalRecords" - ] - }, - "ApiKey": { - "type": "object", - "properties": { "createdAt": { "type": "string", "format": "date-time", - "description": "ISO 8601 timestamp of when the token was created", - "example": "2026-01-15T10:00:00.000Z" + "description": "When the job was submitted.", + "example": "2025-01-15T10:00:00.000Z" }, - "enabled": { - "type": "boolean", - "description": "Whether the token can currently authenticate. Organization tokens may be disabled by admins; personal and MCP tokens are always `true` (revocation deletes them).", - "example": true + "error": { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": "Machine-readable error code.", + "example": "QUERY_EXECUTION_ERROR" + }, + "detail": { + "type": "string", + "description": "Additional error detail or context.", + "example": "The query timed out after 300 seconds" + }, + "message": { + "type": "string", + "description": "Human-readable error message.", + "example": "Column 'revenue' not found in table 'orders'" + } + }, + "required": [ + "message" + ], + "additionalProperties": {}, + "description": "Error details explaining why the job failed. Only present in FAILED state." + }, + "executionStartedAt": { + "type": "string", + "format": "date-time", + "description": "When execution began. Present once the job transitions from QUEUED to EXECUTING. May be absent on jobs that failed or were cancelled before execution started.", + "example": "2025-01-15T10:00:05.000Z" }, "id": { "type": "string", "format": "uuid", - "description": "Unique identifier for the token", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "The unique identifier for this job.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "membershipId": { + "modelId": { "type": [ "string", "null" ], "format": "uuid", - "description": "Membership ID of the user the token is scoped to. Null for organization-level tokens.", - "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" + "description": "The shared model ID used for query generation.", + "example": "770e8400-e29b-41d4-a716-446655440002" }, - "name": { + "omniChatUrl": { "type": "string", - "description": "Human-readable name for the token", - "example": "CI deployment key" + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" }, - "type": { + "organizationId": { + "type": "string", + "format": "uuid", + "description": "The organization that owns this job.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "progress": { + "type": [ + "object", + "null" + ], + "properties": { + "iteration": { + "type": "integer", + "description": "Current iteration number. The AI may take multiple iterations to refine queries and generate a complete answer.", + "example": 2 + }, + "message": { + "type": "string", + "description": "Human-readable status message describing what the AI is currently doing.", + "example": "Running query: Top products by revenue" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When this progress update was recorded.", + "example": "2025-01-15T10:00:08.000Z" + } + }, + "required": [ + "iteration", + "message", + "updatedAt" + ], + "description": "Real-time progress information. Only present in EXECUTING state. Null if no progress has been reported yet. Updated in real-time as the AI works through iterations." + }, + "prompt": { + "type": "string", + "description": "The natural language prompt that was submitted.", + "example": "What are the top 5 products by revenue?" + }, + "resultSummary": { + "type": "string", + "description": "Markdown-formatted summary of the job result. Only present in COMPLETE state. For the full result with query details and data, use GET /api/v1/ai/jobs/{jobId}/result.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "state": { "type": "string", "enum": [ - "organization", - "personal", - "mcp" + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" ], - "description": "Token type: `organization` (org-level), `personal` (user-created personal access token), or `mcp` (MCP OAuth grant).", - "example": "organization" + "description": "Current state of the job. Terminal states are COMPLETE, FAILED, and CANCELLED. Poll until the job reaches a terminal state.", + "example": "QUEUED" + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "Topic name used to scope query generation, or null if the AI selected the topic automatically.", + "example": "order_items" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "When the job record was last modified.", + "example": "2025-01-15T10:00:05.000Z" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "The user ID who created (or is associated with) this job.", + "example": "990e8400-e29b-41d4-a716-446655440004" } }, "required": [ + "branchId", + "conversationId", "createdAt", - "enabled", "id", - "membershipId", - "name", - "type" + "modelId", + "omniChatUrl", + "organizationId", + "prompt", + "state", + "topicName", + "updatedAt", + "userId" ] }, - "ApiKeyUpdateBody": { - "type": "object", - "properties": { - "enabled": { - "type": "boolean", - "description": "Set to `false` to disable the token, `true` to re-enable it. Only organization-level tokens may be disabled; personal and MCP tokens do not support this.", - "example": false - } - }, - "required": [ - "enabled" - ], - "additionalProperties": false - }, - "ApiKeyDeleteResponse": { + "AiJobCancelResponse": { "type": "object", "properties": { - "message": { + "jobId": { "type": "string", - "description": "Human-readable description of the outcome", - "example": "API token revoked" + "format": "uuid", + "description": "The job ID that was requested to cancel.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "success": { - "type": "boolean", + "state": { + "type": "string", "enum": [ - true + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" ], - "description": "Always `true` on a successful revocation" + "description": "The job state after the cancellation attempt. CANCELLED if the cancellation was successful. If the job was already in a terminal state (COMPLETE, FAILED, CANCELLED), the current state is returned unchanged — the endpoint is idempotent.", + "example": "CANCELLED" } }, "required": [ - "message", - "success" + "jobId", + "state" ] }, - "DbtEnvironmentListResponse": { + "AiJobResultResponse": { "type": "object", "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { + "actions": { "type": "array", "items": { - "$ref": "#/components/schemas/DbtEnvironmentItem" - } + "$ref": "#/components/schemas/AiJobAction" + }, + "description": "Ordered list of actions the AI took during execution. Each action represents a step such as generating a query, executing it, or synthesizing a final answer." + }, + "message": { + "type": "string", + "description": "The AI's final response message in Markdown format. This is the complete answer to the original prompt, incorporating data from all executed queries.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "omniChatUrl": { + "type": "string", + "format": "uri", + "description": "URL to view this conversation in the Omni chat interface. Opens the chat session where the job actions and results are visible.", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" + }, + "resultSummary": { + "type": "string", + "description": "Summary of the job result. Typically matches the final message content.", + "example": "### Top 5 Products by Revenue\n\n1. **Sunglasses** - $678,994\n2. **Jeans** - $475,072" + }, + "topic": { + "type": "string", + "description": "The topic name used for query generation.", + "example": "order_items" + } + }, + "additionalProperties": {} + }, + "AiJobAction": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "The AI's explanation of what it is doing in this step, written in natural language.", + "example": "I'll generate a query to find the top 5 products by total revenue." + }, + "result": { + "$ref": "#/components/schemas/AiJobActionQueryResult" + }, + "timestamp": { + "type": "string", + "description": "ISO 8601 timestamp when this action occurred.", + "example": "2025-01-15T10:00:10.000Z" + }, + "type": { + "type": "string", + "description": "The type of action. Common types include \"generate_query\" (query generation and execution) and \"summarize\" (final answer synthesis).", + "example": "generate_query" } }, "required": [ - "pageInfo", - "records" - ] + "message", + "timestamp", + "type" + ], + "additionalProperties": {} }, - "DbtEnvironmentItem": { + "AiJobActionQueryResult": { "type": "object", "properties": { - "id": { + "csvResult": { "type": "string", - "format": "uuid", - "description": "Unique environment identifier" + "description": "Query results formatted as CSV text.", + "example": "Name,Total Revenue\nRay-Ban Sunglasses,\"678,994.41\"\nLevi's 501 Jeans,\"475,072.00\"" }, - "isDefaultEnvironment": { + "csvResultWasTruncated": { "type": "boolean", - "description": "Whether this is the default environment" + "description": "Whether the CSV data was truncated due to size limits. If true, the full result set may contain additional rows not included in csvResult.", + "example": false }, - "name": { + "hasResults": { + "type": "boolean", + "description": "Whether the query returned any data rows.", + "example": true + }, + "query": { + "type": "object", + "additionalProperties": {}, + "description": "The semantic query definition that was executed. This can be used with the POST /api/v1/query/run endpoint to re-run the query." + }, + "queryName": { "type": "string", - "description": "Environment name" + "description": "Human-readable name describing what this query retrieves.", + "example": "Top 5 Products by Revenue" }, - "ownerId": { - "type": [ - "string", - "null" + "status": { + "type": "string", + "enum": [ + "success", + "error" ], - "description": "User ID of the environment owner, or null if not a personal environment" + "description": "Whether the query executed successfully.", + "example": "success" }, - "targetDatabase": { - "type": [ - "string", - "null" - ], - "description": "Target database override" + "totalRowCount": { + "type": "integer", + "description": "Total number of rows returned by the query.", + "example": 5 + } + }, + "required": [ + "csvResult", + "csvResultWasTruncated", + "hasResults", + "query", + "queryName", + "status", + "totalRowCount" + ], + "description": "Query result data. Only present for generate_query action types." + }, + "ApiError422": { + "type": "object", + "properties": { + "error": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "No Arrow IPC data available for visualization" + } + }, + "required": [ + "error" + ] + }, + "AiBrandingResponse": { + "type": "object", + "properties": { + "body": { + "type": "string", + "description": "Body / description copy shown beneath the headline on AI helper landing surfaces.", + "example": "Ask a data question to get started. I can help refine answers, adjust charts, or surface new areas to explore." }, - "targetName": { - "type": [ - "string", - "null" - ], - "description": "Target name override" + "headline": { + "type": "string", + "description": "Short headline shown on AI helper landing surfaces.", + "example": "What would you like to know?" }, - "targetRole": { + "logoUrl": { "type": [ "string", "null" ], - "description": "Target role override" + "format": "uri", + "description": "Absolute URL to a custom AI helper logo. `null` when the org has not configured a custom logo — clients should render their default avatar (e.g. Blobby).", + "example": "https://example.com/blobby.png" }, - "targetSchema": { + "name": { "type": "string", - "description": "Target schema" + "description": "Display name for the AI helper. Defaults to `Omni Agent` when no custom branding is set.", + "example": "Blobby" }, - "variables": { + "placeholder": { + "type": "string", + "description": "Placeholder text for the AI helper's prompt input.", + "example": "Ask a question about your data..." + } + }, + "required": [ + "body", + "headline", + "logoUrl", + "name", + "placeholder" + ] + }, + "AiConversationsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { "type": "array", "items": { - "$ref": "#/components/schemas/DbtEnvironmentResponseVariable" + "$ref": "#/components/schemas/AiConversation" }, - "description": "Environment variables" + "description": "Conversations ordered by updatedAt descending." } }, "required": [ - "id", - "isDefaultEnvironment", - "name", - "ownerId", - "targetDatabase", - "targetName", - "targetRole", - "targetSchema", - "variables" + "pageInfo", + "records" ] }, - "DbtEnvironmentResponseVariable": { + "PageInfo": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Variable ID" - }, - "isSecret": { + "hasNextPage": { "type": "boolean", - "description": "Whether the variable value is secret" - }, - "name": { - "type": "string", - "description": "Variable name" + "description": "Whether more results are available" }, - "value": { + "nextCursor": { "type": [ "string", "null" ], - "description": "Variable value (null for secret variables)" + "description": "Cursor for fetching the next page" + }, + "pageSize": { + "type": "number", + "description": "Number of results per page" + }, + "totalRecords": { + "type": "number", + "description": "Total number of records matching the query" } }, "required": [ - "id", - "isSecret", - "name", - "value" + "hasNextPage", + "nextCursor", + "pageSize", + "totalRecords" ] }, - "DbtEnvironmentCreateBody": { + "AiConversation": { "type": "object", "properties": { - "name": { + "createdAt": { "type": "string", - "minLength": 1, - "description": "Environment name", - "example": "PR_1111_Expose" - }, - "ownerId": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", - "example": null + "format": "date-time", + "description": "When the conversation was started.", + "example": "2025-01-15T10:00:00.000Z" }, - "targetDatabase": { - "type": [ - "string", - "null" - ], - "default": null, - "description": "Target database override", - "example": "analytics_dev" + "id": { + "type": "string", + "format": "uuid", + "description": "Conversation ID. Pass as conversationId on subsequent /api/v1/ai/jobs submissions to continue this conversation.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "targetName": { + "lastPrompt": { "type": [ "string", "null" ], - "default": null, - "description": "Target name override", - "example": null + "description": "The most recent user prompt in this conversation, useful for displaying a one-line summary in a list.", + "example": "What were our top products last week?" }, - "targetRole": { + "name": { "type": [ "string", "null" ], - "default": null, - "description": "Target role override", - "example": null + "description": "Conversation title. Set by the AI after the first turn; null on brand-new sessions.", + "example": "Top products last week" }, - "targetSchema": { + "updatedAt": { "type": "string", - "minLength": 1, - "description": "Target schema for this environment", - "example": "PR_1111_Expose" - }, - "variables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtEnvironmentVariable" - }, - "default": [], - "description": "Environment variables" + "format": "date-time", + "description": "When the conversation was last touched (most recent prompt or AI activity).", + "example": "2025-01-15T10:01:30.000Z" } }, "required": [ + "createdAt", + "id", + "lastPrompt", "name", - "targetSchema" + "updatedAt" ] }, - "DbtEnvironmentVariable": { + "AiConversationDetailResponse": { "type": "object", "properties": { - "isSecret": { - "type": "boolean", - "description": "Whether the variable value is secret" + "createdAt": { + "type": "string", + "format": "date-time" }, - "name": { + "id": { "type": "string", - "minLength": 1, - "description": "Variable name" + "format": "uuid" }, - "value": { + "messages": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiConversationMessage" + }, + "description": "Messages in chronological order. Alternating user / assistant turns." + }, + "name": { + "type": [ + "string", + "null" + ] + }, + "updatedAt": { "type": "string", - "description": "Variable value" + "format": "date-time" } }, "required": [ - "isSecret", + "createdAt", + "id", + "messages", "name", - "value" + "updatedAt" ] }, - "DbtEnvironmentUpdateBody": { + "AiConversationMessage": { "type": "object", "properties": { - "name": { + "createdAt": { "type": "string", - "minLength": 1, - "description": "Environment name", - "example": "PR_1111_Expose" + "format": "date-time", + "description": "When this turn was recorded.", + "example": "2025-01-15T10:00:00.000Z" }, - "ownerId": { + "jobId": { "type": [ "string", "null" ], - "default": null, - "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", - "example": null + "format": "uuid", + "description": "The agentic job that produced this assistant turn. Only set for assistant messages — clients use it to fetch the rendered chart via GET /api/v1/ai/jobs/{jobId}/vis. Null when the turn predates jobs or when we could not associate one.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "targetDatabase": { + "omniChatUrl": { "type": [ "string", "null" ], - "default": null, - "description": "Target database override", - "example": "analytics_dev" + "format": "uri", + "description": "Deep link to the assistant turn in the Omni chat UI. Null for user turns, and for assistant turns produced outside the Agentic API (where no AgenticJob row exists).", + "example": "https://my-org.omni.co/chat/660e8400-e29b-41d4-a716-446655440001" }, - "targetName": { - "type": [ - "string", - "null" + "role": { + "type": "string", + "enum": [ + "user", + "assistant" ], - "default": null, - "description": "Target name override", - "example": null + "description": "Speaker — `user` for prompts the user submitted, `assistant` for Blobby's responses.", + "example": "user" }, - "targetRole": { + "text": { + "type": "string", + "description": "Markdown content of the message. For assistant turns this is the same string returned by /api/v1/ai/jobs/{jobId}/result#message.", + "example": "What were our top products last week?" + } + }, + "required": [ + "createdAt", + "jobId", + "omniChatUrl", + "role", + "text" + ] + }, + "ApiKeyListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiKey" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "ApiKey": { + "type": "object", + "properties": { + "createdAt": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp of when the token was created", + "example": "2026-01-15T10:00:00.000Z" + }, + "enabled": { + "type": "boolean", + "description": "Whether the token can currently authenticate. A disabled token cannot authenticate but remains visible until deleted.", + "example": true + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the token", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "membershipId": { "type": [ "string", "null" ], - "default": null, - "description": "Target role override", - "example": null + "format": "uuid", + "description": "Membership ID of the user the token is scoped to. Null for organization-level tokens.", + "example": "b2c3d4e5-f6a7-8901-bcde-f12345678901" }, - "targetSchema": { + "name": { "type": "string", - "minLength": 1, - "description": "Target schema for this environment", - "example": "PR_1111_Expose" + "description": "Human-readable name for the token", + "example": "CI deployment key" }, - "variables": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtEnvironmentVariableUpdateOrNew" - }, - "default": [], - "description": "Environment variables. Variables with an id update existing ones; variables without an id create new ones." + "type": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Token type: `organization` (org-level), `personal` (user-created personal access token), or `mcp` (MCP OAuth grant).", + "example": "organization" } }, "required": [ + "createdAt", + "enabled", + "id", + "membershipId", "name", - "targetSchema" + "type" ] }, - "DbtEnvironmentVariableUpdateOrNew": { - "oneOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentVariableUpdate" - }, - { - "$ref": "#/components/schemas/DbtEnvironmentVariable" + "ApiKeyUpdateBody": { + "type": "object", + "properties": { + "enabled": { + "type": "boolean", + "description": "Set to `false` to disable the token, `true` to re-enable it.", + "example": false } - ] + }, + "required": [ + "enabled" + ], + "additionalProperties": false }, - "DbtEnvironmentDeleteResponse": { + "ApiKeyDeleteResponse": { "type": "object", "properties": { "message": { "type": "string", - "description": "Confirmation message", - "example": "dbt environment deleted successfully" + "description": "Human-readable description of the outcome", + "example": "API token revoked" }, "success": { "type": "boolean", - "description": "Whether the deletion was successful", - "example": true + "enum": [ + true + ], + "description": "Always `true` on a successful revocation" } }, "required": [ @@ -1372,7 +1704,7 @@ "success" ] }, - "ContentListResponse": { + "DbtEnvironmentListResponse": { "type": "object", "properties": { "pageInfo": { @@ -1381,120 +1713,7 @@ "records": { "type": "array", "items": { - "oneOf": [ - { - "allOf": [ - { - "$ref": "#/components/schemas/ApiDocument" - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "document" - ] - } - }, - "required": [ - "type" - ] - } - ] - }, - { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier" - }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Content name" - }, - "owner": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "User ID of the owner" - }, - "name": { - "type": "string", - "description": "Name of the owner" - } - }, - "required": [ - "id", - "name" - ], - "description": "Content owner" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Content access scope" - }, - "_count": { - "type": "object", - "properties": { - "documents": { - "type": "number", - "description": "Number of documents" - }, - "favorites": { - "type": "number", - "description": "Number of users who favorited" - } - }, - "required": [ - "documents", - "favorites" - ], - "description": "Folder counts" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels" - }, - "path": { - "type": "string", - "description": "Full path to the folder", - "example": "sales-reports/q1-2026" - }, - "url": { - "type": "string", - "description": "URL to view the folder in the Omni UI.", - "example": "https://org.omni.co/f/sales-reports" - }, - "type": { - "type": "string", - "enum": [ - "folder" - ] - } - }, - "required": [ - "id", - "name", - "owner", - "scope", - "path", - "url", - "type" - ] - } - ] + "$ref": "#/components/schemas/DbtEnvironmentItem" } } }, @@ -1503,406 +1722,428 @@ "records" ] }, - "OwnerInternal": { + "DbtEnvironmentItem": { "type": "object", "properties": { "id": { "type": "string", - "description": "Owner membership ID" - }, - "name": { - "type": "string", - "description": "Owner display name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Content owner" - }, - "ContentShareScope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Content access scope" - }, - "InternalFolder": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "description": "Folder ID" + "format": "uuid", + "description": "Unique environment identifier" }, - "name": { - "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Folder name" + "isDefaultEnvironment": { + "type": "boolean", + "description": "Whether this is the default environment" }, - "path": { - "type": "string", - "description": "Folder path" + "isDeferralEnabled": { + "type": "boolean", + "description": "Whether dbt deferral is enabled for this environment. Always false for the default (production) environment — the backend rejects enabling it there." }, - "scope": { - "allOf": [ - { - "$ref": "#/components/schemas/ContentShareScope" - }, - { - "description": "Folder access scope" - } - ] - } - }, - "required": [ - "id", - "name", - "path", - "scope" - ], - "description": "Parent folder" - }, - "ApiDocument": { - "type": "object", - "properties": { "name": { "type": "string", - "minLength": 1, - "maxLength": 255, - "description": "Content name" - }, - "owner": { - "$ref": "#/components/schemas/OwnerInternal" - }, - "scope": { - "$ref": "#/components/schemas/ContentShareScope" + "description": "Environment name" }, - "_count": { - "type": "object", - "properties": { - "favorites": { - "type": "number", - "description": "Number of users who favorited" - }, - "views": { - "type": "number", - "description": "Number of views" - } - }, - "required": [ - "favorites", - "views" + "ownerId": { + "type": [ + "string", + "null" ], - "description": "Document counts" - }, - "connectionId": { - "type": "string", - "description": "Connection ID" - }, - "deleted": { - "type": "boolean", - "description": "Whether document is deleted" + "description": "User ID of the environment owner, or null if not a personal environment" }, - "description": { + "targetDatabase": { "type": [ "string", "null" ], - "description": "Document description" - }, - "folder": { - "$ref": "#/components/schemas/InternalFolder" - }, - "hasDashboard": { - "type": "boolean", - "description": "Whether document has a dashboard" - }, - "identifier": { - "type": "string", - "description": "Document identifier" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Applied labels" + "description": "Target database override" }, - "lastViewedAt": { + "targetName": { "type": [ "string", "null" ], - "format": "date-time", - "description": "Last time the dashboard was viewed" + "description": "Target name override" }, - "updatedAt": { + "targetRole": { "type": [ "string", "null" ], - "format": "date-time", - "description": "Last updated timestamp" + "description": "Target role override" }, - "url": { + "targetSchema": { "type": "string", - "description": "URL to view the document. Returns dashboard URL if document has a dashboard, otherwise workbook URL.", - "example": "https://org.omni.co/dashboards/abc123" + "description": "Target schema" }, - "visits": { - "type": [ - "number", - "null" - ], - "description": "Number of dashboard visits" + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentResponseVariable" + }, + "description": "Environment variables" } }, "required": [ + "id", + "isDefaultEnvironment", + "isDeferralEnabled", "name", - "owner", - "scope", - "connectionId", - "deleted", - "folder", - "hasDashboard", - "identifier", - "updatedAt", - "url" + "ownerId", + "targetDatabase", + "targetName", + "targetRole", + "targetSchema", + "variables" ] }, - "DashboardsDownloadResponse": { + "DbtEnvironmentResponseVariable": { "type": "object", "properties": { - "job_id": { + "id": { "type": "string", "format": "uuid", - "description": "ID of the download job. Use this to poll for download status.", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Variable ID" }, - "message": { + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" + }, + "name": { "type": "string", - "description": "Status message", - "example": "Download initiated successfully" + "description": "Variable name" + }, + "value": { + "type": [ + "string", + "null" + ], + "description": "Variable value (null for secret variables)" } }, "required": [ - "job_id", - "message" + "id", + "isSecret", + "name", + "value" ] }, - "DashboardsDownloadBody": { + "DbtEnvironmentCreateBody": { "type": "object", "properties": { - "enableFormatting": { + "isDeferralEnabled": { "type": "boolean", "default": false, - "description": "Compatible with csv, xlsx & json formats. If true, formatting will be enabled in the output. Note: If true for json format, a queryIdentifierMapKey is required.", + "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", "example": false }, - "expandTablesToShowAllRows": { - "type": "boolean", - "description": "Compatible with pdf and png formats. If true, up to 1,000 rows in table visualizations will be included in the delivery. Note: This parameter cannot be used when paperFormat: fit_page.", - "example": false - }, - "filterConfig": { - "description": "An object specifying the filter conditions to apply to the task. The filter key specified must already exist in the dashboard.", - "example": { - "status": [ - "active", - "pending" - ] - } - }, - "format": { + "name": { "type": "string", - "enum": [ - "pdf", - "png", - "csv", - "xlsx", - "json" - ], - "description": "Output format for the download: pdf, png, csv, xlsx, or json", - "example": "pdf" - }, - "hideHiddenFields": { - "type": "boolean", - "default": false, - "description": "Compatible with csv & xlsx formats. If true, fields marked as hidden won't be displayed in the output.", - "example": false - }, - "hideTitle": { - "type": "boolean", - "default": false, - "description": "Compatible with pdf & png formats. If true, the content's title will be hidden in the output.", - "example": false - }, - "maxRowLimit": { - "type": "number", - "minimum": 1, - "description": "Compatible with csv, json, & xlsx formats. Used with overrideRowLimit. Specifies the maximum number of rows.", - "example": 1000 - }, - "overrideRowLimit": { - "type": "boolean", - "default": false, - "description": "Compatible with csv, json, & xlsx formats. If true, the default row limit will be overridden. Note: If true for json and xlsx formats, a queryIdentifierMapKey is required.", - "example": false + "minLength": 1, + "description": "Environment name", + "example": "PR_1111_Expose" }, - "paperFormat": { - "type": "string", - "enum": [ - "a3", - "a4", - "fit_page", - "legal", - "letter", - "tabloid" + "ownerId": { + "type": [ + "string", + "null" ], - "description": "Compatible with pdf formats. Defines the paper format (size) of the resulting PDF. Must be one of: a3, a4, letter, legal, fit_page, tabloid.", - "example": "letter" + "default": null, + "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", + "example": null }, - "paperOrientation": { - "type": "string", - "enum": [ - "portrait", - "landscape" + "targetDatabase": { + "type": [ + "string", + "null" ], - "description": "Compatible with pdf formats. Defines the paper orientation of the resulting PDF. Must be one of: portrait, landscape.", - "example": "landscape" - }, - "queryIdentifierMapKey": { - "type": "string", - "description": "Required for single tile tasks. The ID of the query to include in a single tile task. Must reference a valid query in the dashboard.", - "example": "Jmn2r3KV" - }, - "showContentLink": { - "type": "boolean", - "default": true, - "description": "Compatible with all formats except link_only. If true, a link to the content will be shown in the output.", - "example": true - }, - "showFilters": { - "type": "boolean", - "default": true, - "description": "Compatible with all formats except link_only & csv. If true, filters will be shown in the output.", - "example": true + "default": null, + "description": "Target database override", + "example": "analytics_dev" }, - "singleColumnLayout": { - "type": "boolean", - "description": "Compatible with pdf and png formats. If true, dashboard tiles will be arranged into a single vertical column.", - "example": false + "targetName": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target name override", + "example": null }, - "useCache": { - "type": "boolean", - "default": false, - "description": "If true, allow scheduled queries to use cached results instead of always running fresh queries.", - "example": false + "targetRole": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target role override", + "example": null }, - "filename": { + "targetSchema": { "type": "string", "minLength": 1, - "maxLength": 255, - "description": "Custom filename for the downloaded file (without extension)", - "example": "monthly-report" + "description": "Target schema for this environment", + "example": "PR_1111_Expose" + }, + "variables": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtEnvironmentVariable" + }, + "default": [], + "description": "Environment variables" } }, "required": [ - "format" - ], - "additionalProperties": false + "name", + "targetSchema" + ] }, - "DashboardFiltersResponse": { + "DbtEnvironmentVariable": { "type": "object", "properties": { - "controls": { - "description": "Control configuration object. Keys are control IDs, values contain controlType, filterId, label, etc." - }, - "filterOrder": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Ordered list of filter IDs defining display order", - "example": [ - "filter_abc123", - "filter_def456" - ] + "isSecret": { + "type": "boolean", + "description": "Whether the variable value is secret" }, - "filters": { - "description": "Filter configuration object. Keys are filter IDs, values contain fieldName, viewName, kind, defaultValue, etc." + "name": { + "type": "string", + "minLength": 1, + "description": "Variable name" }, - "identifier": { + "value": { "type": "string", - "description": "Dashboard identifier", - "example": "12db1a0a" + "description": "Variable value" } }, "required": [ - "filterOrder", - "identifier" + "isSecret", + "name", + "value" ] }, - "DashboardsUpdateFiltersBody": { + "DbtEnvironmentUpdateBody": { "type": "object", "properties": { - "clearExistingDraft": { + "isDeferralEnabled": { "type": "boolean", "default": false, - "description": "When true, discards any existing draft before applying updates. Required when updating a published document that already has a draft." + "description": "Whether to enable dbt deferral for this environment. Ignored (forced to false) for the default (production) environment.", + "example": false }, - "controls": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": {}, - "additionalProperties": {} - }, - "description": "Partial control updates. Keys are control IDs that must exist in the dashboard." + "name": { + "type": "string", + "minLength": 1, + "description": "Environment name", + "example": "PR_1111_Expose" }, - "filterOrder": { + "ownerId": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "User ID of the environment owner. Used to mark development environments belonging to a specific user.", + "example": null + }, + "targetDatabase": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target database override", + "example": "analytics_dev" + }, + "targetName": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target name override", + "example": null + }, + "targetRole": { + "type": [ + "string", + "null" + ], + "default": null, + "description": "Target role override", + "example": null + }, + "targetSchema": { + "type": "string", + "minLength": 1, + "description": "Target schema for this environment", + "example": "PR_1111_Expose" + }, + "variables": { "type": "array", "items": { - "type": "string" - }, - "description": "New order for filters. All filter IDs must exist in the dashboard." - }, - "filters": { - "type": "object", - "additionalProperties": { - "type": "object", - "properties": {}, - "additionalProperties": {} + "$ref": "#/components/schemas/DbtEnvironmentVariableUpdateOrNew" }, - "description": "Partial filter updates. Keys are filter IDs that must exist in the dashboard." + "default": [], + "description": "Environment variables. Variables with an id update existing ones; variables without an id create new ones." } - } + }, + "required": [ + "name", + "targetSchema" + ] }, - "DocumentsListResponse": { + "DbtEnvironmentVariableUpdateOrNew": { + "oneOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentVariableUpdate" + }, + { + "$ref": "#/components/schemas/DbtEnvironmentVariable" + } + ] + }, + "DbtEnvironmentDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Confirmation message", + "example": "dbt environment deleted successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the deletion was successful", + "example": true + } + }, + "required": [ + "message", + "success" + ] + }, + "ContentListResponse": { "type": "object", "properties": { "pageInfo": { - "allOf": [ - { - "$ref": "#/components/schemas/PageInfo" - }, - { - "description": "Pagination information" - } - ] + "$ref": "#/components/schemas/PageInfo" }, "records": { "type": "array", "items": { - "$ref": "#/components/schemas/Document" - }, - "description": "List of documents" + "oneOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/ApiDocument" + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "document" + ] + } + }, + "required": [ + "type" + ] + } + ] + }, + { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Content name" + }, + "owner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "User ID of the owner" + }, + "name": { + "type": "string", + "description": "Name of the owner" + } + }, + "required": [ + "id", + "name" + ], + "description": "Content owner" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Content access scope" + }, + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents" + }, + "favorites": { + "type": "number", + "description": "Number of users who favorited" + } + }, + "required": [ + "documents", + "favorites" + ], + "description": "Folder counts" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels" + }, + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "sales-reports/q1-2026" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/sales-reports" + }, + "type": { + "type": "string", + "enum": [ + "folder" + ] + } + }, + "required": [ + "id", + "name", + "owner", + "scope", + "path", + "url", + "type" + ] + } + ] + } } }, "required": [ @@ -1910,15 +2151,92 @@ "records" ] }, - "Document": { + "OwnerInternal": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Owner membership ID" + }, + "name": { + "type": "string", + "description": "Owner display name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Content owner" + }, + "ContentShareScope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Content access scope" + }, + "InternalFolder": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Folder ID" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Folder name" + }, + "path": { + "type": "string", + "description": "Folder path" + }, + "scope": { + "allOf": [ + { + "$ref": "#/components/schemas/ContentShareScope" + }, + { + "description": "Folder access scope" + } + ] + } + }, + "required": [ + "id", + "name", + "path", + "scope" + ], + "description": "Parent folder" + }, + "ApiDocument": { "type": "object", "properties": { + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Content name" + }, + "owner": { + "$ref": "#/components/schemas/OwnerInternal" + }, + "scope": { + "$ref": "#/components/schemas/ContentShareScope" + }, "_count": { "type": "object", "properties": { "favorites": { "type": "number", - "description": "Number of users who favorited this document" + "description": "Number of users who favorited" }, "views": { "type": "number", @@ -1929,15 +2247,15 @@ "favorites", "views" ], - "description": "Document counts (included when _count is in include param)" + "description": "Document counts" }, "connectionId": { "type": "string", - "description": "Connection ID the document is associated with" + "description": "Connection ID" }, "deleted": { "type": "boolean", - "description": "Whether the document is deleted (archived)" + "description": "Whether document is deleted" }, "description": { "type": [ @@ -1947,45 +2265,34 @@ "description": "Document description" }, "folder": { - "$ref": "#/components/schemas/DocumentFolder" + "$ref": "#/components/schemas/InternalFolder" + }, + "hasApp": { + "type": "boolean", + "description": "Whether document has an app" }, "hasDashboard": { "type": "boolean", - "description": "Whether the document has an associated dashboard" + "description": "Whether document has a dashboard" }, "identifier": { "type": "string", - "description": "Document identifier", - "example": "abc123" + "description": "Document identifier" }, "labels": { "type": "array", "items": { "type": "string" }, - "description": "Labels applied to the document (included when labels is in include param)" - }, - "name": { - "type": "string", - "description": "Document name" - }, - "owner": { - "$ref": "#/components/schemas/DocumentOwner" - }, - "scope": { - "type": "string", - "enum": [ - "restricted", - "organization" - ], - "description": "Document access scope" + "description": "Applied labels" }, - "type": { - "type": "string", - "enum": [ - "document" + "lastViewedAt": { + "type": [ + "string", + "null" ], - "description": "Content type" + "format": "date-time", + "description": "Last time the dashboard was viewed" }, "updatedAt": { "type": [ @@ -1997,101 +2304,451 @@ }, "url": { "type": "string", - "description": "URL to view the document. Returns dashboard URL if document has a dashboard, otherwise workbook URL.", + "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", "example": "https://org.omni.co/dashboards/abc123" + }, + "visits": { + "type": [ + "number", + "null" + ], + "description": "Number of dashboard visits" } }, "required": [ + "name", + "owner", + "scope", "connectionId", "deleted", "folder", + "hasApp", "hasDashboard", "identifier", - "name", - "owner", - "scope", - "type", "updatedAt", "url" ] }, - "DocumentFolder": { - "type": [ - "object", - "null" - ], + "DashboardsDownloadResponse": { + "type": "object", "properties": { - "id": { + "job_id": { "type": "string", - "description": "Folder ID" + "format": "uuid", + "description": "ID of the download job. Use this to poll for download status.", + "example": "123e4567-e89b-12d3-a456-426614174000" }, - "name": { + "message": { "type": "string", - "description": "Folder name" + "description": "Status message", + "example": "Download initiated successfully" + } + }, + "required": [ + "job_id", + "message" + ] + }, + "DashboardsDownloadBody": { + "type": "object", + "properties": { + "enableFormatting": { + "type": "boolean", + "default": false, + "description": "Compatible with csv, xlsx & json formats. If true, formatting will be enabled in the output. Note: If true for json format, a queryIdentifierMapKey is required.", + "example": false }, - "path": { + "expandTablesToShowAllRows": { + "type": "boolean", + "description": "Compatible with pdf and png formats. If true, up to 1,000 rows in table visualizations will be included in the delivery. Note: This parameter cannot be used when paperFormat: fit_page.", + "example": false + }, + "filterConfig": { + "description": "An object specifying the filter conditions to apply to the task. The filter key specified must already exist in the dashboard.", + "example": { + "status": [ + "active", + "pending" + ] + } + }, + "format": { "type": "string", - "description": "Folder path" + "enum": [ + "pdf", + "png", + "csv", + "xlsx", + "json" + ], + "description": "Output format for the download: pdf, png, csv, xlsx, or json", + "example": "pdf" }, - "scope": { + "hideHiddenFields": { + "type": "boolean", + "default": false, + "description": "Compatible with csv & xlsx formats. If true, fields marked as hidden won't be displayed in the output.", + "example": false + }, + "hideTitle": { + "type": "boolean", + "default": false, + "description": "Compatible with pdf & png formats. If true, the content's title will be hidden in the output.", + "example": false + }, + "maxRowLimit": { + "type": "number", + "minimum": 1, + "description": "Compatible with csv, json, & xlsx formats. Used with overrideRowLimit. Specifies the maximum number of rows.", + "example": 1000 + }, + "overrideRowLimit": { + "type": "boolean", + "default": false, + "description": "Compatible with csv, json, & xlsx formats. If true, the default row limit will be overridden. Note: If true for json and xlsx formats, a queryIdentifierMapKey is required.", + "example": false + }, + "paperFormat": { "type": "string", "enum": [ - "restricted", - "organization" + "a3", + "a4", + "fit_page", + "legal", + "letter", + "tabloid" ], - "description": "Folder access scope" + "description": "Compatible with pdf formats. Defines the paper format (size) of the resulting PDF. Must be one of: a3, a4, letter, legal, fit_page, tabloid.", + "example": "letter" + }, + "paperOrientation": { + "type": "string", + "enum": [ + "portrait", + "landscape" + ], + "description": "Compatible with pdf formats. Defines the paper orientation of the resulting PDF. Must be one of: portrait, landscape.", + "example": "landscape" + }, + "queryIdentifierMapKey": { + "type": "string", + "description": "Required for single tile tasks. The ID of the query to include in a single tile task. Must reference a valid query in the dashboard.", + "example": "Jmn2r3KV" + }, + "showContentLink": { + "type": "boolean", + "default": true, + "description": "Compatible with all formats except link_only. If true, a link to the content will be shown in the output.", + "example": true + }, + "showFilters": { + "type": "boolean", + "default": true, + "description": "Compatible with all formats except link_only & csv. If true, filters will be shown in the output.", + "example": true + }, + "singleColumnLayout": { + "type": "boolean", + "description": "Compatible with pdf and png formats. If true, dashboard tiles will be arranged into a single vertical column.", + "example": false + }, + "useCache": { + "type": "boolean", + "default": false, + "description": "If true, allow scheduled queries to use cached results instead of always running fresh queries.", + "example": false + }, + "filename": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Custom filename for the downloaded file (without extension)", + "example": "monthly-report" } }, "required": [ - "id", - "name", - "path", - "scope" + "format" ], - "description": "Folder containing the document" + "additionalProperties": false }, - "DocumentOwner": { + "DashboardFiltersResponse": { "type": "object", "properties": { - "id": { - "type": "string", - "description": "Owner membership ID" + "controls": { + "description": "Control configuration object. Keys are control IDs, values contain controlType, filterId, label, etc." }, - "name": { + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter IDs defining display order", + "example": [ + "filter_abc123", + "filter_def456" + ] + }, + "filters": { + "description": "Filter configuration object. Keys are filter IDs, values contain fieldName, viewName, kind, defaultValue, etc." + }, + "identifier": { "type": "string", - "description": "Owner display name" + "description": "Dashboard identifier", + "example": "12db1a0a" } }, "required": [ - "id", - "name" - ], - "description": "Document owner" + "filterOrder", + "identifier" + ] }, - "DocumentsCreateResponse": { + "DashboardsUpdateFiltersBody": { "type": "object", "properties": { - "dashboard": { + "clearExistingDraft": { + "type": "boolean", + "default": false, + "description": "When true, discards any existing draft before applying updates. Required when updating a published document that already has a draft." + }, + "controls": { "type": "object", - "properties": { - "dashboardId": { - "type": "string", - "description": "Dashboard ID" - }, - "id": { - "type": "string", - "description": "Dashboard ID" - } + "additionalProperties": { + "type": "object", + "properties": {}, + "additionalProperties": {} }, - "required": [ - "dashboardId", - "id" - ], - "additionalProperties": {}, - "description": "Created dashboard" + "description": "Partial control updates. Keys are control IDs that must exist in the dashboard." }, - "workbook": { - "type": "object", + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "New order for filters. All filter IDs must exist in the dashboard." + }, + "filters": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": {}, + "additionalProperties": {} + }, + "description": "Partial filter updates. Keys are filter IDs that must exist in the dashboard." + } + } + }, + "DocumentsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Document" + }, + "description": "List of documents" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Document": { + "type": "object", + "properties": { + "_count": { + "type": "object", + "properties": { + "favorites": { + "type": "number", + "description": "Number of users who favorited this document" + }, + "views": { + "type": "number", + "description": "Number of views" + } + }, + "required": [ + "favorites", + "views" + ], + "description": "Document counts (included when _count is in include param)" + }, + "connectionId": { + "type": "string", + "description": "Connection ID the document is associated with" + }, + "deleted": { + "type": "boolean", + "description": "Whether the document is deleted (archived)" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description" + }, + "folder": { + "$ref": "#/components/schemas/DocumentFolder" + }, + "hasApp": { + "type": "boolean", + "description": "Whether the document has an associated app" + }, + "hasDashboard": { + "type": "boolean", + "description": "Whether the document has an associated dashboard" + }, + "identifier": { + "type": "string", + "description": "Document identifier", + "example": "abc123" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels applied to the document (included when labels is in include param)" + }, + "name": { + "type": "string", + "description": "Document name" + }, + "owner": { + "$ref": "#/components/schemas/DocumentOwner" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Document access scope" + }, + "type": { + "type": "string", + "enum": [ + "document" + ], + "description": "Content type" + }, + "updatedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Last updated timestamp" + }, + "url": { + "type": "string", + "description": "URL to view the document. Returns the dashboard URL if it has a dashboard, the app URL if it has an app, otherwise the workbook URL.", + "example": "https://org.omni.co/dashboards/abc123" + } + }, + "required": [ + "connectionId", + "deleted", + "folder", + "hasDashboard", + "identifier", + "name", + "owner", + "scope", + "type", + "updatedAt", + "url" + ] + }, + "DocumentFolder": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "description": "Folder ID" + }, + "name": { + "type": "string", + "description": "Folder name" + }, + "path": { + "type": "string", + "description": "Folder path" + }, + "scope": { + "type": "string", + "enum": [ + "restricted", + "organization" + ], + "description": "Folder access scope" + } + }, + "required": [ + "id", + "name", + "path", + "scope" + ], + "description": "Folder containing the document" + }, + "DocumentOwner": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Owner membership ID" + }, + "name": { + "type": "string", + "description": "Owner display name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Document owner" + }, + "DocumentsCreateResponse": { + "type": "object", + "properties": { + "dashboard": { + "type": "object", + "properties": { + "dashboardId": { + "type": "string", + "description": "Dashboard ID" + }, + "id": { + "type": "string", + "description": "Dashboard ID" + } + }, + "required": [ + "dashboardId", + "id" + ], + "additionalProperties": {}, + "description": "Created dashboard" + }, + "workbook": { + "type": "object", "properties": { "documentId": { "type": "string", @@ -2180,10 +2837,13 @@ }, "description": { "type": "string", + "maxLength": 500, "description": "Query presentation description" }, "name": { "type": "string", + "minLength": 1, + "maxLength": 144, "description": "Query presentation name" }, "prefersChart": { @@ -2217,11 +2877,16 @@ }, "subTitle": { "type": "string", + "maxLength": 250, "description": "Subtitle" }, "topicName": { - "type": "string", - "description": "Topic name" + "type": [ + "string", + "null" + ], + "maxLength": 256, + "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." }, "visConfig": { "$ref": "#/components/schemas/ApiVisConfig" @@ -2247,7 +2912,10 @@ "description": "Optional document identifier. If omitted, an identifier is auto-generated. Must be unique within the organization." }, "ApiVisConfig": { - "type": "object", + "type": [ + "object", + "null" + ], "properties": { "config": { "type": "object", @@ -2517,10 +3185,13 @@ }, "description": { "type": "string", + "maxLength": 500, "description": "Description" }, "name": { "type": "string", + "minLength": 1, + "maxLength": 144, "description": "Query presentation name" }, "prefersChart": { @@ -2530,16 +3201,26 @@ "query": { "description": "Query definition" }, + "queryIdentifierMapKey": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "Round-trip preservation hint. When the value matches an existing key on the document, the tile keeps its map key (and dashboard containers stay attached). Omit for new tiles. Must be a positive integer string (e.g. \"1\", \"2\", \"10\")." + }, "resultConfig": { "description": "Result config" }, "subTitle": { "type": "string", + "maxLength": 250, "description": "Subtitle" }, "topicName": { - "type": "string", - "description": "Topic name" + "type": [ + "string", + "null" + ], + "maxLength": 256, + "description": "Topic name. Omit or pass null for raw-SQL tiles or any tile with no semantic topic." }, "visConfig": { "$ref": "#/components/schemas/ApiVisConfig" @@ -2720,6 +3401,10 @@ "type": "boolean", "description": "Allow using dashboard AI" }, + "canUseTimezoneOverride": { + "type": "boolean", + "description": "Allow timezone override" + }, "canViewWorkbook": { "type": "boolean", "description": "Allow viewing workbook" @@ -2888,10 +3573,122 @@ } } }, - "DocumentsDuplicateResponse": { + "DocumentsListDraftsResponse": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ApiDraft" + } + }, + "ApiDraft": { "type": "object", "properties": { - "dashboardId": { + "branch": { + "$ref": "#/components/schemas/ApiDraftBranch" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "When the draft was created" + }, + "createdBy": { + "$ref": "#/components/schemas/ApiDraftActor" + }, + "draftOutOfDate": { + "type": "boolean", + "description": "True when the published document was published more recently than the draft was created (the draft is based on a stale baseline)" + }, + "identifier": { + "type": "string", + "description": "Draft workbook identifier — use this to address the draft" + }, + "lastEditedBy": { + "allOf": [ + { + "$ref": "#/components/schemas/ApiDraftActor" + }, + { + "description": "User who most recently edited the draft" + } + ] + }, + "publishedIdentifier": { + "type": "string", + "description": "Identifier of the published document the draft is for" + }, + "status": { + "$ref": "#/components/schemas/ApiDraftStatus" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Most recent edit time on the draft workbook" + }, + "workbookModelId": { + "type": "string", + "format": "uuid", + "description": "omni_model ID for the draft workbook" + } + }, + "required": [ + "branch", + "createdAt", + "createdBy", + "draftOutOfDate", + "identifier", + "lastEditedBy", + "publishedIdentifier", + "status", + "updatedAt", + "workbookModelId" + ] + }, + "ApiDraftBranch": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Branch (omni model) ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Branch the draft is attached to, or null for a draft on main" + }, + "ApiDraftActor": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Display name" + } + }, + "required": [ + "name" + ], + "description": "User who created the draft" + }, + "ApiDraftStatus": { + "type": "string", + "enum": [ + "active", + "archived" + ], + "description": "Lifecycle status: \"active\" for current drafts, \"archived\" for soft-deleted drafts (retained ~7 days)" + }, + "DocumentsDuplicateResponse": { + "type": "object", + "properties": { + "dashboardId": { "type": "string", "description": "New dashboard ID" }, @@ -3017,54 +3814,7 @@ "principals" ] }, - "EmbedSsoGenerateSessionResponse": { - "type": "object", - "properties": { - "sessionId": { - "type": "string", - "description": "Session ID to use for embedding Omni content" - } - }, - "required": [ - "sessionId" - ] - }, - "EmbedSsoGenerateSessionBody": { - "type": "object", - "properties": { - "externalId": { - "type": "string", - "description": "External identifier for the user (from your system)", - "example": "user-123" - }, - "groups": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Optional list of group names to assign to the user", - "example": [ - "engineering", - "sales" - ] - }, - "name": { - "type": "string", - "description": "Display name for the user", - "example": "John Doe" - }, - "userAttributes": { - "type": "object", - "additionalProperties": {}, - "description": "Optional user attributes for row-level security" - } - }, - "required": [ - "externalId", - "name" - ] - }, - "FoldersListResponse": { + "DocumentsListFavoritesResponse": { "type": "object", "properties": { "pageInfo": { @@ -3080,68 +3830,9 @@ "records": { "type": "array", "items": { - "type": "object", - "properties": { - "_count": { - "type": "object", - "properties": { - "documents": { - "type": "number", - "description": "Number of documents in the folder" - }, - "favorites": { - "type": "number", - "description": "Number of users who have favorited this folder" - } - }, - "required": [ - "documents", - "favorites" - ], - "description": "Count statistics for the folder" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique folder identifier" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels associated with the folder" - }, - "name": { - "type": "string", - "description": "Name of the folder", - "example": "My Reports" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the folder owner" - }, - "path": { - "type": "string", - "description": "Full path to the folder", - "example": "/shared/reports/my-reports" - }, - "url": { - "type": "string", - "description": "URL to view the folder in the Omni UI.", - "example": "https://org.omni.co/f/my-reports" - } - }, - "required": [ - "id", - "name", - "ownerId", - "path", - "url" - ] + "$ref": "#/components/schemas/DocumentFavoriteUser" }, - "description": "List of folders" + "description": "Users who favorited this document" } }, "required": [ @@ -3149,1744 +3840,22830 @@ "records" ] }, - "FoldersCreateResponse": { + "DocumentFavoriteUser": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "ID of the created folder" - }, - "name": { - "type": "string", - "description": "Name of the created folder" + "email": { + "type": [ + "string", + "null" + ], + "description": "Favoriting user's email. Null when the user has no resolvable email — e.g. an embed-SSO favoriter whose embed session did not provide one." }, - "ownerId": { + "favoritedAt": { "type": "string", - "format": "uuid", - "description": "User ID of the folder owner" + "description": "ISO 8601 timestamp when the user favorited the document" }, - "path": { + "name": { "type": "string", - "description": "Full path to the folder" + "description": "Favoriting user's display name" }, - "scope": { + "userId": { "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Share scope of the folder" + "description": "Membership ID of the user who favorited the document (use with other v1 endpoints' userId parameter)" } }, "required": [ - "id", + "email", + "favoritedAt", "name", - "ownerId", - "path", - "scope" + "userId" ] }, - "FoldersCreateBody": { + "DocumentsV2CreateResponse": { "type": "object", "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "Name of the folder to create", - "example": "My New Folder" - }, - "parentFolderId": { - "type": "string", - "format": "uuid", - "description": "Parent folder ID (omit to create at root level)" + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." }, - "scope": { + "identifier": { "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Share scope for the folder" + "description": "Identifier of the newly created document." }, - "userId": { + "name": { "type": "string", - "format": "uuid", - "description": "User ID to create the folder as (for org-scoped API keys only)" + "description": "Document name." } }, "required": [ + "description", + "identifier", "name" ] }, - "FoldersDeleteResponse": { + "DocumentsV2CreateBody": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the folder was deleted successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersUpdateResponse": { - "type": "object", - "properties": { - "id": { - "type": "string", + "containers": { + "$ref": "#/components/schemas/Containers" + }, + "controls": { + "$ref": "#/components/schemas/ControlsPatchExternal" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "folderId": { + "type": [ + "string", + "null" + ], "format": "uuid", - "description": "Folder ID" + "description": "Folder to create the document in. When omitted, defaults to the caller’s personal \"My documents\" (requires permission to save personal content — otherwise the request is rejected)." }, - "name": { - "type": "string", - "description": "Updated folder name" + "identifier": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentIdentifier" + }, + { + "description": "Identifier for the new document. Must be unique within the organization. Auto-generated when omitted." + } + ] }, - "path": { + "modelId": { "type": "string", - "description": "Updated URL path segment for the folder (the folder's own segment only)" - } - }, - "required": [ - "id", - "name", - "path" - ] - }, - "FoldersUpdateBody": { - "type": "object", - "properties": { + "format": "uuid", + "description": "Base workbook model the document is built on — a SHARED model, or a SHARED_EXTENSION with `allowAsWorkbookBase = true`." + }, "name": { "type": "string", "minLength": 1, - "description": "New display name for the folder", - "example": "Q1 Reports" + "maxLength": 254, + "description": "Document name." }, - "path": { - "type": "string", - "minLength": 1, - "pattern": "^[a-zA-Z0-9-]+$", - "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", - "example": "q1-reports" + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsPatchExternal" }, - "resolvePathConflict": { - "type": "boolean", - "default": false, - "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." - } - } - }, - "FoldersGetPermissionsResponse": { - "type": "object", - "properties": { - "permits": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "description": "Whether access boost is enabled for this permit" - }, - "role": { - "type": "string", - "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", - "example": "VIEWER" - }, - "userGroupId": { - "type": "string", - "description": "User group ID if this is a group permit" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID if this is a user permit" - } - }, - "required": [ - "role" - ] - }, - "description": "List of permission permits for the folder" - } - }, - "required": [ - "permits" - ] - }, - "FoldersAddPermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were added successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersAddPermissionsBody": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "default": false, - "description": "Whether to grant access boost" + "settings": { + "$ref": "#/components/schemas/SettingsPatchExternal" }, - "role": { + "summary": { "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" - ], - "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", - "example": "VIEWER" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to grant permission to" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to grant permission to" + "minLength": 1, + "maxLength": 255, + "description": "Caller-supplied note describing the create, written to the history audit trail. Defaults to \"Created document\" when omitted." } }, "required": [ - "role" + "modelId", + "name" ], "additionalProperties": false }, - "FoldersUpdatePermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were updated successfully" - } + "Containers": { + "type": "array", + "items": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/PageContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + } + ] }, - "required": [ - "success" - ] + "description": "Container layout array (grid / stack / page / reference containers, recursively nested). The server validates the full structure on apply." }, - "FoldersUpdatePermissionsBody": { + "GridContainer": { "type": "object", "properties": { - "accessBoost": { - "type": "boolean", - "description": "Whether to grant access boost" + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" }, - "role": { + "instanceKey": { "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" - ], - "description": "New content role to assign" + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to update permissions for" + "name": { + "type": "string", + "description": "Human-readable name for the container, used for easier reference in logic and design" }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to update permissions for" - } - }, - "additionalProperties": false - }, - "FoldersRevokePermissionsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were revoked successfully" - } - }, - "required": [ - "success" - ] - }, - "FoldersRevokePermissionsBody": { - "type": "object", - "properties": { - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to revoke permissions from" + "aspectRatio": { + "type": "string" }, - "userIds": { + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + }, + "after": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "before": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "children": { "type": "array", "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to revoke permissions from" - } - }, - "additionalProperties": false - }, - "LabelsListResponse": { - "type": "object", - "properties": { - "labels": { - "type": "array", - "items": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + "anyOf": [ + { + "allOf": [ + { + "$ref": "#/components/schemas/ReferenceContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" + { + "allOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + { + "allOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" + { + "allOf": [ + { + "anyOf": [ + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "as": { + "type": "string", + "enum": [ + "chart", + "result", + "ai", + "metadata" + ], + "description": "Render mode: \"chart\" for visualization, \"result\" for data table, \"ai\" for AI summary, \"metadata\" for query metadata" + }, + "format": { + "type": "string", + "enum": [ + "subtitle", + "description", + "name" + ], + "description": "Display format when as is \"ai\" or \"metadata\": \"name\" (metadata only), \"subtitle\", or \"description\"" + }, + "id": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "The query presentation ID this content item references" + }, + "name": { + "type": "string", + "description": "Display name for this query item" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "inline" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tooltip" + ] + } + }, + "required": [ + "as" + ] + } + ], + "description": "Display mode: \"inline\" renders directly, \"tooltip\" shows on hover" + }, + "content": { + "type": "string", + "description": "The text content to display (supports markdown)" + }, + "name": { + "type": "string", + "description": "Display name for this text item (e.g., title, subtitle)" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "textAlign": { + "type": "string", + "enum": [ + "start", + "center", + "end" + ], + "description": "Text alignment: \"start\", \"center\", or \"end\"" + }, + "type": { + "type": "string", + "enum": [ + "inline-text" + ] + } + }, + "required": [ + "instanceKey", + "content", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tabs" + ] + }, + "variant": { + "type": "string", + "enum": [ + "underline", + "bordered" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "buttons" + ] + }, + "variant": { + "type": "string", + "enum": [ + "segment", + "toggle", + "pills" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "list" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "dropdown" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + } + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "includeControls": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uri": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "inline-page-switcher" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the rich text content block" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "control" + ] + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "filter" + ] + }, + "appearance": { + "type": "object", + "properties": { + "control": { + "type": "string", + "enum": [ + "buttonToggle", + "dropdown" + ] + }, + "display": { + "type": "string", + "enum": [ + "inline", + "popover" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "instanceKey", + "type" + ], + "additionalProperties": {} + } + ] + }, + { + "type": "object", + "properties": { + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number" + }, + "w": { + "type": "number" + }, + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] + } + }, + "required": [ + "gridPosition" + ] + } + ] } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" ] - }, - "description": "List of labels" - } - }, - "required": [ - "labels" - ] - }, - "LabelsCreateResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + } }, - "name": { + "containerType": { "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + "enum": [ + "grid" + ] }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsCreateBody": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "default": null, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "default": null, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "default": false, - "description": "Show label on homepage. Requires admin permissions." - }, - "name": { - "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" - }, - "verified": { - "type": "boolean", - "default": false, - "description": "Mark as verified label. Requires admin permissions." - } - }, - "required": [ - "name" - ] - }, - "LabelsGetResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsUpdateResponse": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" - } - }, - "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" - ] - }, - "LabelsUpdateBody": { - "type": "object", - "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Show label on homepage. Requires admin permissions to modify." + "gridPosition": { + "type": "object", + "properties": { + "h": { + "type": "number", + "description": "Height in grid units (default: 36 for charts)" + }, + "w": { + "type": "number", + "description": "Width in grid columns on a 24-column grid. Common widths: 24 (full), 12 (half), 8 (third), 6 (quarter). x + w must not exceed 24." + }, + "x": { + "type": "number", + "description": "X position on a 24-column grid (0=left edge, 12=middle). Items side-by-side share the same y with complementary x values." + }, + "y": { + "type": "number", + "description": "Y position in grid units (0=top, higher values=lower on page)" + } + }, + "required": [ + "h", + "w", + "x", + "y" + ] }, - "name": { - "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" + "metadata": { + "type": "object", + "properties": { + "attachedQueryKey": { + "type": "string", + "description": "Set by the auto-add-tile flow when this container was generated for a specific workbook tab. The server removes containers with a matching `attachedQueryKey` when that tab is deleted. The reducer clears this when the user adds unrelated content (a different query, filter, text tile, page switcher, or sub-container)." + } + }, + "description": "Optional bookkeeping for this container (e.g. `attachedQueryKey` for auto-placed tiles)" }, - "verified": { - "type": "boolean", - "description": "Mark as verified label. Requires admin permissions to modify." - } - } - }, - "ModelsListResponse": { - "type": "object", - "properties": { - "pageInfo": { - "allOf": [ + "padding": { + "anyOf": [ { - "$ref": "#/components/schemas/PageInfo" + "type": "number", + "enum": [ + 0 + ] }, { - "description": "Pagination information" - } - ] - }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseModelId": { - "type": [ - "string", - "null" - ], - "description": "Base model ID for branch/extension models" - }, - "branches": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Branch ID" - }, - "name": { - "type": "string", - "description": "Branch name" - } - }, - "required": [ - "id", - "name" - ] - }, - "description": "Active branches (if include=activeBranches)" - }, - "connectionId": { - "type": [ - "string", - "null" - ], - "description": "Connection ID" - }, - "createdAt": { - "type": "string", - "description": "Creation timestamp" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Deletion timestamp" - }, - "id": { - "type": "string", - "description": "Model ID" - }, - "modelKind": { - "type": [ - "string", - "null" - ], - "description": "Model kind" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Model name" - }, - "updatedAt": { - "type": "string", - "description": "Last update timestamp" - } + "type": "number", + "enum": [ + 0.5 + ] }, - "required": [ - "baseModelId", - "connectionId", - "createdAt", - "deletedAt", - "id", - "modelKind", - "name", - "updatedAt" - ] - }, - "description": "List of model records" - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "CreateModelSchemaBase": { - "type": "object", - "properties": { - "accessGrants": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoostable": { - "type": "boolean" - }, - "allowedValues": { - "type": "array", - "items": { - "type": "string" - } - }, - "codeComments": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "ignored": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "userAttribute": { - "type": "string" - } + { + "type": "number", + "enum": [ + 1 + ] }, - "required": [ - "accessBoostable", - "name" - ] - }, - "description": "Access grants for the model" - }, - "allowAsWorkbookBase": { - "type": "boolean", - "description": "Allow this model as a workbook base" - }, - "baseModelId": { - "type": "string", - "description": "Base model ID for extension or branch models" - }, - "connectionId": { - "type": "string", - "description": "Connection ID for the model" - }, - "modelKind": { - "anyOf": [ { - "type": "string", + "type": "number", "enum": [ - "SCHEMA" + 2 ] }, { - "type": "string", + "type": "number", "enum": [ - "SHARED" + 3 ] }, { - "type": "string", + "type": "number", "enum": [ - "SHARED_EXTENSION" + 4 ] }, { - "type": "string", + "type": "number", "enum": [ - "BRANCH" + 5 ] - } - ], - "default": "SCHEMA", - "description": "Kind of model to create" - }, - "modelName": { - "type": "string", - "description": "Name for the model" - }, - "usesIsolatedBranches": { - "type": "boolean", - "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" - } - }, - "required": [ - "connectionId" - ] - }, - "ModelsUpdateResponse": { - "type": "object", - "properties": { - "model": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Model ID" }, - "name": { - "type": "string", - "description": "Updated model name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Updated model details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - } - }, - "required": [ - "model", - "success" - ] - }, - "ModelsUpdateBody": { - "type": "object", - "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "New name for the model", - "example": "My Renamed Model" - } - }, - "required": [ - "name" - ] - }, - "JobsGetStatusResponse": { - "type": "object", - "properties": { - "job_id": { - "type": "string", - "description": "The job ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "job_type": { - "type": "string", - "description": "The type of job (e.g., REFRESH_SCHEMA)", - "example": "REFRESH_SCHEMA" - }, - "status": { - "type": "string", - "enum": [ - "IN_PROGRESS", - "COMPLETED", - "FAILED" - ], - "description": "Current status of the job", - "example": "COMPLETED" - } - }, - "required": [ - "job_id", - "job_type", - "status" - ] - }, - "ModelsGetSchemasResponse": { - "type": "object", - "properties": { - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" - } - }, - "required": [ - "schemas" - ] - }, - "ModelsGetViewResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "views": { - "type": "array", - "items": { - "type": "object", - "properties": { - "description": { - "type": "string", - "description": "View description" - }, - "fields": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Field name" + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] }, - "type": { - "type": "string", + { + "type": "number", "enum": [ - "dimension", - "measure", - "filter" - ], - "description": "Field type" + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] } - }, - "required": [ - "name", - "type" ] }, - "description": "Fields in the view" - }, - "hidden": { - "type": "boolean", - "description": "Whether the view is hidden" - }, - "label": { - "type": "string", - "description": "View label" - }, - "name": { - "type": "string", - "description": "View name" - } + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] }, - "required": [ - "fields", - "name" - ] - }, - "description": "List of views" - } - }, - "required": [ - "success", - "views" - ] - }, - "ModelsUpdateViewBody": { - "type": "object", - "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the view" - }, - "description": { - "type": "string", - "description": "View description" - }, - "format": { - "type": "string", - "description": "View format" - }, - "hidden": { - "type": "boolean", - "description": "Whether the view is hidden" - }, - "label": { - "type": "string", - "description": "View label" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the view" - } - } - }, - "ModelsUpdateFieldBody": { - "type": "object", - "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "allValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Deprecated: use sampleValues instead" - }, - "binBoundaries": { - "type": "array", - "items": { - "type": "number" - }, - "description": "Bin boundaries for binned fields" - }, - "binLabels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels for bins" - }, - "description": { - "type": "string", - "description": "Field description" - }, - "drillFields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Drill-down fields" - }, - "elseValue": { - "type": "string", - "description": "Else value for grouped fields" - }, - "filters": { - "type": "object", - "additionalProperties": {}, - "description": "Filters for the field" - }, - "format": { - "type": "string", - "description": "Field format" - }, - "groupFilters": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Group filters" - }, - "groupLabel": { - "type": "string", - "description": "Group label" - }, - "groupNames": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Group names" - }, - "hidden": { - "type": "boolean", - "description": "Whether the field is hidden" - }, - "ignored": { - "type": "boolean", - "description": "Whether the field is ignored" - }, - "isCalc": { - "type": "boolean", - "description": "Whether this is a calculation field" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "newFieldName": { - "type": "string", - "description": "New field name (for rename)" - }, - "newViewName": { - "type": "string", - "description": "New view name (for move)" - }, - "sampleValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Sample values for the field" - }, - "sql": { - "type": "string", - "description": "SQL expression for the field" - }, - "synonyms": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Synonyms for the field" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" - }, - "topicContext": { - "type": "string", - "description": "Topic context for the field" - } - } - }, - "ModelsListTopicsResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "topics": { - "type": "array", - "items": { - "type": "object", - "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" - }, - "description": { - "type": "string", - "description": "Topic description" - }, - "group_label": { - "type": "string", - "description": "Group label" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "name": { - "type": "string", - "description": "Topic name" - } - }, - "required": [ - "base_view_name", - "name" - ] - }, - "description": "List of topics" - } - }, - "required": [ - "success", - "topics" - ] - }, - "ModelsGetTopicResponse": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "topic": { - "type": "object", - "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" - }, - "description": { - "type": "string", - "description": "Topic description" - }, - "group_label": { - "type": "string", - "description": "Group label" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "name": { - "type": "string", - "description": "Topic name" - }, - "relationships": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Relationships for the topic" - }, - "views": { + { "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Views available in the topic" - } - }, - "required": [ - "base_view_name", - "name", - "relationships", - "views" - ], - "description": "Topic details with relationships and views" - } - }, - "required": [ - "success", - "topic" - ] - }, - "ModelsUpdateTopicBody": { - "type": "object", - "properties": { - "description": { - "type": "string", - "description": "Topic description" - }, - "groupLabel": { - "type": "string", - "description": "Group label for the topic" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "newTopicName": { - "type": "string", - "description": "New topic name (for rename)" - } - } - }, - "ModelsCreateFieldBody": { - "type": "object", - "properties": { - "aggregateType": { - "type": "string", - "description": "Aggregate type for measures" - }, - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "description": { - "type": "string", - "description": "Field description" - }, - "fieldName": { - "type": "string", - "description": "Field name", - "example": "total_revenue" - }, - "format": { - "type": "string", - "description": "Field format" - }, - "hidden": { - "type": "boolean", - "description": "Whether the field is hidden" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "sql": { - "type": "string", - "description": "SQL expression for the field" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" - }, - "topicContext": { - "type": "string", - "description": "Topic context for topic-scoped fields" - }, - "viewName": { - "type": "string", - "description": "View to add the field to", - "example": "orders" - } - }, - "required": [ - "fieldName", - "viewName" - ] - }, - "ModelsRefreshResponse": { - "type": "object", - "properties": { - "jobId": { - "type": "string", - "description": "Job ID for the refresh operation" - }, - "modelId": { - "type": "string", - "description": "Model ID being refreshed" - }, - "status": { - "type": "string", - "enum": [ - "running", - "completed", - "failed" - ], - "description": "Current status of the refresh" - } - }, - "required": [ - "jobId", - "modelId", - "status" - ] - }, - "ModelsValidateResponse": { - "type": "object", - "properties": { - "issues": { - "type": "array", - "items": { - "type": "object", - "properties": { - "field": { - "type": "string", - "description": "Field name with the issue" - }, - "message": { - "type": "string", - "description": "Validation issue message" - }, - "severity": { - "type": "string", - "enum": [ - "error", - "warning" - ], - "description": "Issue severity" - }, - "view": { - "type": "string", - "description": "View name with the issue" - } + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] }, - "required": [ - "message", - "severity" - ] - }, - "description": "List of validation issues" - }, - "valid": { - "type": "boolean", - "description": "Whether the model is valid" - } - }, - "required": [ - "issues", - "valid" - ] - }, - "ModelsMigrateBody": { - "type": "object", - "properties": { - "branchName": { - "type": "string", - "description": "Branch name for the target model" - }, - "commitMessage": { - "type": "string", - "description": "Commit message for git sync" - }, - "gitRef": { - "type": "string", - "description": "Git reference" - }, - "targetModelId": { - "type": "string", - "format": "uuid", - "description": "Target model ID to migrate to" - } - }, - "required": [ - "targetModelId" - ] - }, - "ModelsDbtExposuresResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" - }, - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/DbtExposureWithMeta" - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "DbtExposureWithMeta": { - "type": "object", - "properties": { - "dashboard_identifier": { - "type": "string", - "description": "Identifier of the dashboard that generated this exposure" + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + } + ] }, - "deduplication_name": { + "style": { "type": "string", - "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." - }, - "exposure": { - "$ref": "#/components/schemas/DbtExposure" + "pattern": "^[a-z0-9-]+$" } }, "required": [ - "dashboard_identifier", - "deduplication_name", - "exposure" - ] + "instanceKey", + "children", + "containerType" + ], + "description": "Grid container — children are positioned on a grid (each carries a gridPosition)." }, - "DbtExposure": { + "StackContainer": { "type": "object", "properties": { - "depends_on": { - "type": "array", - "items": { - "type": "string" - }, - "description": "List of dbt model references (e.g. ref('model_name'))", - "example": [ - "ref('orders')", - "ref('customers')" - ] + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" }, - "label": { + "instanceKey": { "type": "string", - "description": "Original dashboard name" + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." }, "name": { "type": "string", - "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", - "example": "my_dashboard" + "description": "Human-readable name for the container, used for easier reference in logic and design" }, - "owner": { - "$ref": "#/components/schemas/DbtExposureOwner" + "aspectRatio": { + "type": "string" }, - "type": { + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + }, + "after": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "align": { "type": "string", "enum": [ - "dashboard", - "notebook", - "analysis", - "ml", - "application" + "flex-start", + "flex-end", + "center", + "stretch" ], - "description": "Type of the exposure", - "example": "dashboard" - }, - "url": { - "type": "string", - "description": "URL of the dashboard" - } - }, - "required": [ - "depends_on", - "name", - "owner", - "type" - ], - "description": "The dbt exposure for this dashboard." - }, - "DbtExposureOwner": { - "type": "object", - "properties": { - "email": { - "type": "string", - "description": "Email of the dashboard owner" - }, - "name": { - "type": "string", - "description": "Name of the dashboard owner" - } - }, - "required": [ - "email", - "name" - ] - }, - "ModelsBranchDbtBody": { - "type": "object", - "properties": { - "dbt_environment_id": { - "type": "string", - "format": "uuid", - "description": "ID of the dbt environment to activate on this branch", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "dbt_git_branch": { - "type": "string", - "description": "Git branch to associate with the dbt environment", - "example": "feature/new-metrics" - } - }, - "required": [ - "dbt_environment_id" - ] - }, - "ModelsMergeBranchResponse": { - "type": "object", - "properties": { - "failed_drafts_count": { - "type": "number", - "description": "Number of drafts that failed to publish" - }, - "git_synced": { - "type": "boolean", - "description": "Whether git was synced" - }, - "published_drafts_count": { - "type": "number", - "description": "Number of drafts published" - }, - "success": { - "type": "boolean", - "description": "Whether the merge succeeded" - } - }, - "required": [ - "failed_drafts_count", - "git_synced", - "published_drafts_count", - "success" - ] - }, - "ModelsMergeBranchBody": { - "type": "object", - "properties": { - "commit_message": { - "type": "string", - "description": "Custom commit message for git sync" - }, - "delete_branch": { - "type": "boolean", - "default": false, - "description": "Delete the branch after merging" - }, - "force_override_git_settings": { - "type": "boolean", - "default": false, - "description": "Override PR-required or git-follower settings" - }, - "publish_drafts": { - "type": "boolean", - "default": true, - "description": "Publish branch-attached drafts" - } - } - }, - "ModelsCommitResponse": { - "type": "object", - "properties": { - "did_sync": { - "type": "boolean", - "description": "Whether a sync operation was performed against git" - }, - "git_sha": { - "type": [ - "string", - "null" - ], - "description": "The git SHA of the commit that was pushed (null if no commit was needed)" - }, - "in_sync": { - "type": "boolean", - "description": "Whether the branch is in sync with git after the operation" - }, - "pr_url": { - "type": [ - "string", - "null" - ], - "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." - } - }, - "required": [ - "did_sync", - "git_sha", - "in_sync", - "pr_url" - ] - }, - "ModelsCommitBody": { - "type": "object", - "properties": { - "allow_branch_exists": { - "type": "boolean", - "default": true, - "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", - "example": true - }, - "branch_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to commit.", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "commit_message": { - "type": "string", - "minLength": 1, - "description": "Commit message for the git commit.", - "example": "Add new orders view" + "description": "Cross-axis alignment of children (e.g., center, stretch)" }, - "require_branch_exists": { - "type": "boolean", - "default": false, - "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", - "example": false - } - }, - "required": [ - "branch_id", - "commit_message" - ] - }, - "ModelsCacheResetResponse": { - "type": "object", - "properties": { - "cache_reset": { - "type": "object", - "properties": { - "created_at": { - "type": [ - "string", - "null" - ], - "description": "Creation timestamp" - }, - "model_id": { - "type": "string", - "description": "Model ID" - }, - "policy_name": { - "type": "string", - "description": "Cache policy name" - }, - "reset_at": { - "type": [ - "string", - "null" - ], - "description": "Reset timestamp" + "before": { + "anyOf": [ + { + "$ref": "#/components/schemas/StackContainer" }, - "updated_at": { - "type": [ - "string", - "null" - ], - "description": "Last update timestamp" + { + "$ref": "#/components/schemas/ReferenceContainer" } - }, - "required": [ - "created_at", - "model_id", - "policy_name", - "reset_at", - "updated_at" - ], - "description": "Cache reset details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - } - }, - "required": [ - "cache_reset", - "success" - ] - }, - "ModelsCacheResetBody": { - "type": "object", - "properties": { - "resetAt": { - "type": "string", - "description": "ISO-8601 timestamp for when to reset the cache", - "example": "2024-01-15T12:00:00Z" - } - } - }, - "ModelsGitGetResponse": { - "type": "object", - "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false + ] }, - "cloneUrl": { + "children": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "as": { + "type": "string", + "enum": [ + "chart", + "result", + "ai", + "metadata" + ], + "description": "Render mode: \"chart\" for visualization, \"result\" for data table, \"ai\" for AI summary, \"metadata\" for query metadata" + }, + "format": { + "type": "string", + "enum": [ + "subtitle", + "description", + "name" + ], + "description": "Display format when as is \"ai\" or \"metadata\": \"name\" (metadata only), \"subtitle\", or \"description\"" + }, + "id": { + "type": "string", + "pattern": "^[1-9][0-9]*$", + "description": "The query presentation ID this content item references" + }, + "name": { + "type": "string", + "description": "Display name for this query item" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "inline" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tooltip" + ] + } + }, + "required": [ + "as" + ] + } + ], + "description": "Display mode: \"inline\" renders directly, \"tooltip\" shows on hover" + }, + "content": { + "type": "string", + "description": "The text content to display (supports markdown)" + }, + "name": { + "type": "string", + "description": "Display name for this text item (e.g., title, subtitle)" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "textAlign": { + "type": "string", + "enum": [ + "start", + "center", + "end" + ], + "description": "Text alignment: \"start\", \"center\", or \"end\"" + }, + "type": { + "type": "string", + "enum": [ + "inline-text" + ] + } + }, + "required": [ + "instanceKey", + "content", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "appearance": { + "oneOf": [ + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "tabs" + ] + }, + "variant": { + "type": "string", + "enum": [ + "underline", + "bordered" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "buttons" + ] + }, + "variant": { + "type": "string", + "enum": [ + "segment", + "toggle", + "pills" + ] + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "list" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + }, + { + "type": "object", + "properties": { + "as": { + "type": "string", + "enum": [ + "dropdown" + ] + }, + "description": { + "type": "boolean" + } + }, + "required": [ + "as" + ] + } + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "disabled": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "includeControls": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "target": { + "type": "string" + }, + "uri": { + "type": "string" + }, + "value": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "inline-page-switcher" + ] + } + }, + "required": [ + "instanceKey", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "UUID of the rich text content block" + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "text" + ] + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "control" + ] + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string", + "description": "Unique identifier for this specific placement of the content item. Use this key (not the query id) when repositioning or removing items." + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "null" + } + ] + }, + "preset": { + "type": "string", + "pattern": "^[a-z0-9-]+$", + "description": "Visual preset for the content item (e.g., \"tile-align\" for outer spacing to align with tile containers)" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "filter" + ] + }, + "appearance": { + "type": "object", + "properties": { + "control": { + "type": "string", + "enum": [ + "buttonToggle", + "dropdown" + ] + }, + "display": { + "type": "string", + "enum": [ + "inline", + "popover" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "value" + ] + } + }, + "value": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "style": { + "type": "object", + "properties": { + "aspectRatio": { + "type": "string" + }, + "fillSpace": { + "type": "boolean" + }, + "height": { + "type": "string" + }, + "maxHeight": { + "type": "string" + }, + "maxWidth": { + "type": "string" + }, + "minHeight": { + "type": "string" + }, + "minWidth": { + "type": "string" + }, + "width": { + "type": "string" + } + } + } + }, + "required": [ + "instanceKey", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "instanceKey": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "instanceKey", + "type" + ], + "additionalProperties": {} + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + }, + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + } + ] + } + }, + "containerType": { + "type": "string", + "enum": [ + "stack" + ], + "description": "Stack containers lay out children sequentially in a direction (column or row)" + }, + "direction": { + "type": "string", + "enum": [ + "column", + "row" + ], + "description": "Layout direction: \"row\" lays out horizontally, \"column\" stacks vertically (default if not specified)" + }, + "gap": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "number", + "enum": [ + 9 + ] + }, + { + "type": "number", + "enum": [ + 10 + ] + }, + { + "type": "number", + "enum": [ + 11 + ] + }, + { + "type": "number", + "enum": [ + 12 + ] + }, + { + "type": "number", + "enum": [ + 13 + ] + }, + { + "type": "number", + "enum": [ + 14 + ] + }, + { + "type": "number", + "enum": [ + 15 + ] + }, + { + "type": "number", + "enum": [ + 16 + ] + } + ], + "description": "Space between children (CSS size value)" + }, + "justify": { + "type": "string", + "enum": [ + "flex-start", + "flex-end", + "center", + "space-between" + ], + "description": "Main-axis alignment of children (e.g., start, center, end)" + }, + "metadata": { + "type": "object", + "properties": { + "attachedQueryKey": { + "type": "string", + "description": "Set by the auto-add-tile flow when this container was generated for a specific workbook tab. The server removes containers with a matching `attachedQueryKey` when that tab is deleted. The reducer clears this when the user adds unrelated content (a different query, filter, text tile, page switcher, or sub-container)." + } + }, + "description": "Optional bookkeeping for this container (e.g. `attachedQueryKey` for auto-placed tiles)" + }, + "padding": { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + }, + { + "type": "array", + "prefixItems": [ + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + }, + { + "anyOf": [ + { + "type": "number", + "enum": [ + 0 + ] + }, + { + "type": "number", + "enum": [ + 0.5 + ] + }, + { + "type": "number", + "enum": [ + 1 + ] + }, + { + "type": "number", + "enum": [ + 2 + ] + }, + { + "type": "number", + "enum": [ + 3 + ] + }, + { + "type": "number", + "enum": [ + 4 + ] + }, + { + "type": "number", + "enum": [ + 5 + ] + }, + { + "type": "number", + "enum": [ + 6 + ] + }, + { + "type": "number", + "enum": [ + 7 + ] + }, + { + "type": "number", + "enum": [ + 8 + ] + } + ] + } + ] + } + ] + }, + "style": { + "type": "string", + "pattern": "^[a-z0-9-]+$" + }, + "wrap": { + "type": "string", + "enum": [ + "nowrap", + "wrap" + ], + "description": "Whether flex items should wrap to new lines (defaults to nowrap if not specified)" + } + }, + "required": [ + "instanceKey", + "children", + "containerType" + ], + "description": "Stack container — an ordered list of nested children (content, grid, stack, or reference)." + }, + "ReferenceContainer": { + "type": "object", + "properties": { + "containerType": { + "type": "string", + "enum": [ + "reference" + ] + }, + "instanceKey": { + "type": "string" + }, + "referenceKey": { + "type": "string" + } + }, + "required": [ + "containerType", + "instanceKey", + "referenceKey" + ], + "description": "Reference container — points at another container in the collection by its instanceKey." + }, + "PageContainer": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Optional description for the container, providing additional context or information" + }, + "instanceKey": { + "type": "string", + "description": "Unique identifier for this container. Used to reference the container when adding, moving, or removing children." + }, + "name": { + "type": "string", + "description": "Human-readable name for the container, used for easier reference in logic and design" + }, + "breakpoint": { + "type": "string", + "enum": [ + "desktop", + "mobile" + ] + }, + "container": { + "anyOf": [ + { + "$ref": "#/components/schemas/GridContainer" + }, + { + "$ref": "#/components/schemas/StackContainer" + }, + { + "$ref": "#/components/schemas/ReferenceContainer" + } + ] + }, + "containerType": { + "type": "string", + "enum": [ + "page" + ] + }, + "media": { + "type": "string", + "enum": [ + "screen", + "print" + ] + } + }, + "required": [ + "instanceKey", + "container", + "containerType" + ], + "description": "Page container — a top-level page wrapping a single grid, stack, or reference container, optionally per breakpoint/media." + }, + "ControlsPatchExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ControlPatchExternal" + }, + "description": "Controls keyed by control ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete." + }, + "order": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Display order for controls. When present, replaces the existing order." + } + } + }, + "ControlPatchExternal": { + "type": [ + "object", + "null" + ], + "properties": { + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ], + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.)." + }, + "map": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean", + "enum": [ + false + ] + } + ] + }, + "description": "Per-tile field overrides keyed by tab ID. Values are a field name (override) or false (exclude tile from control)." + } + }, + "required": [ + "config" + ] + }, + "JsonValue": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + }, + { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/components/schemas/JsonValue" + }, + { + "type": "null" + } + ] + } + }, + { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/JsonValue" + }, + { + "type": "null" + } + ] + } + } + ], + "description": "Arbitrary JSON value (string, number, boolean, null, object, or array)." + }, + "QueryPresentationsPatchExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/QueryPresentationPatchExternal" + }, + "description": "Query presentations keyed by tab ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete. Capped at 48 entries per patch." + }, + "order": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[1-9][0-9]*$" + }, + "description": "Tab display order. When present, replaces the existing order." + } + } + }, + "QueryPresentationPatchExternal": { + "type": [ + "object", + "null" + ], + "properties": { + "aiConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "description": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "subTitle": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + } + }, + "description": "AI-generated metadata config (subtitle/description auto-generation settings)." + }, + "automaticVis": { + "type": [ + "boolean", + "null" + ], + "description": "When true, the system automatically selects the best visualization type." + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "User-provided tab description." + }, + "editingModelObjectName": { + "type": [ + "string", + "null" + ], + "description": "Model object (view/topic) currently being edited via the dataset/query-view editor. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "editingModelObjectNameChange": { + "type": [ + "string", + "null" + ], + "description": "Pending rename of the model object being edited. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter field names controlling display order on this tab." + }, + "isSql": { + "type": [ + "boolean", + "null" + ], + "description": "Whether this tab is in raw SQL mode." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "User-provided tab name." + }, + "prefersChart": { + "type": "boolean", + "description": "When true, the chart view is shown by default instead of the data table." + }, + "query": { + "type": [ + "object", + "null" + ], + "properties": { + "aiGenerated": { + "type": "boolean", + "description": "True when AI generated this query’s SQL; the AI SQL is shown in the advanced SQL box." + }, + "branch_id": { + "type": "string", + "description": "Branch model ID when querying against a model branch." + }, + "calculations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allow_refs_to_unselected_fields": { + "type": "boolean", + "description": "Set by the Kotlin parser when this calc references fields not selected at the top level (AI SQL-gen produces these; UI-authored calcs do not)." + }, + "calc_name": { + "type": "string", + "description": "Internal identifier for the calculation, used as the column alias." + }, + "description": { + "type": "string", + "description": "Description of the calculation." + }, + "format": { + "type": "string", + "description": "Number/date format string (e.g. \"#,##0.00\")." + }, + "label": { + "type": "string", + "description": "Display label shown in the UI." + }, + "original_formula": { + "type": "string", + "description": "The original Excel-style formula before parsing (e.g. \"=SUM(A1:A10)\")." + }, + "outside_pivot": { + "type": "boolean", + "description": "When true, the calculation is evaluated outside the pivot grouping." + }, + "pushdown": { + "type": [ + "boolean", + "null" + ], + "description": "Per-calc override for whether to evaluate before the row limit. `null` defers to the model-level default." + }, + "sql": { + "type": "string", + "description": "Compiled SQL string produced from the formula." + }, + "sql_expression": { + "description": "Parsed SQL expression tree (serialized)." + }, + "swallow_errors": { + "type": "boolean", + "description": "When true, calculation errors are silently swallowed instead of surfaced." + } + }, + "required": [ + "calc_name" + ], + "additionalProperties": {} + }, + "description": "Table calculations attached to this query." + }, + "column_limit": { + "type": "number", + "description": "Max number of pivot columns to return." + }, + "column_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Column-level aggregation totals, keyed by field name." + }, + "controls": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ] + }, + "description": "Interactive controls (field selectors, PoP controls) attached to this query." + }, + "cube_metadata": { + "type": "object", + "properties": { + "cube_name": { + "type": "string" + }, + "hash_key": { + "type": "string" + }, + "topic_name": { + "type": "string" + } + }, + "required": [ + "cube_name", + "hash_key", + "topic_name" + ], + "additionalProperties": {}, + "description": "Cube-specific metadata (topic name, cube name, hash key) for cube-backed queries." + }, + "custom_summary_types": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Per-field custom summary functions (e.g. SUM, AVG, COUNT)." + }, + "dbtFileName": { + "type": "string", + "description": "dbt file name when this query is backed by a dbt model." + }, + "dbtMode": { + "type": "boolean", + "description": "Whether this query is in dbt mode." + }, + "default_group_by": { + "type": "boolean", + "description": "When true, all dimensions are implicitly included in GROUP BY." + }, + "dimensionIndex": { + "type": "number", + "description": "Index of the primary dimension used for result ordering." + }, + "executableSQL": { + "type": "string", + "description": "Server-compiled SQL string (read-only, set by the backend)." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Model field names selected for the query (dimensions + measures)." + }, + "fill_fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Fields whose missing date/time values should be filled with nulls to create continuous series." + }, + "filters": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Query filters keyed by filter ID." + }, + "filtersUsedInSql": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Filters that were embedded directly in raw SQL (read-only)." + }, + "join_paths_from_topic_name": { + "type": "string", + "description": "Topic name that determines join path precedence for parsed SQL queries." + }, + "join_via_map": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "Virtual topic join path overrides, keyed by view name to ordered join path." + }, + "limit": { + "type": "number", + "description": "Row limit for the query." + }, + "manualSort": { + "type": "boolean", + "description": "When true, the user has explicitly set a custom sort order." + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "label": { + "type": "string" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": {} + }, + "description": "Per-field display metadata (format, label, order)." + }, + "offset": { + "type": "number", + "description": "Row offset for pagination." + }, + "parsed": { + "type": "boolean", + "description": "Whether this raw SQL query has been parsed into a semantic query." + }, + "periodOverPeriodTransposed": { + "type": "boolean", + "description": "Whether the period-over-period comparison columns are transposed." + }, + "period_over_period_computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date_filter_field_name": { + "type": "string", + "description": "The date dimension field this comparison is anchored to." + }, + "date_filter_id": { + "type": "string", + "description": "ID of the date filter being offset (if backed by a dashboard filter)." + }, + "is_dynamic_previous_period": { + "type": "boolean", + "description": "When true, the previous period is calculated dynamically relative to the current filter range." + }, + "periods_ago": { + "type": [ + "number", + "null" + ], + "description": "How many periods back to compare (e.g. 1 = previous period). Null if not set." + }, + "time_unit_name": { + "type": [ + "string", + "null" + ], + "description": "Time grain for the offset (e.g. \"month\", \"year\"). Null if not set." + } + }, + "required": [ + "date_filter_field_name", + "periods_ago", + "time_unit_name" + ], + "additionalProperties": {} + }, + "description": "Period-over-period comparison configurations." + }, + "pivots": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names to pivot on (columns become values)." + }, + "rewriteSql": { + "type": "boolean", + "description": "When true, the backend should rewrite/optimize the SQL." + }, + "row_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Row-level aggregation totals, keyed by field name." + }, + "sorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "column_name": { + "type": "string", + "description": "The model field name to sort by." + }, + "is_column_sort": { + "type": "boolean", + "description": "When true, this sort targets a pivoted column rather than a row dimension." + }, + "pivot_value_map": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ] + }, + "description": "Maps pivot field names to specific pivot values, scoping the sort to a single pivot column." + }, + "sort_descending": { + "type": "boolean", + "description": "When true, sort order is descending." + }, + "subtotal_sort": { + "type": "string", + "description": "Field name whose subtotal row should be used as the sort key." + } + }, + "required": [ + "column_name", + "sort_descending" + ], + "additionalProperties": {} + }, + "description": "Sort clauses applied to the query result set." + }, + "sqlSortsEnabled": { + "type": "boolean", + "description": "Whether user-created sorts are enabled on a raw SQL query." + }, + "staticQueryReferences": { + "type": "object", + "additionalProperties": {}, + "description": "Pre-computed query references for AI chat context. Inner shape is `OmniQuery & { model_id: string }`; left as `unknown` to avoid a recursive zod schema. Validated structurally by consumers when they execute the referenced sub-queries." + }, + "table": { + "type": "string", + "description": "Base view (table) name in the model." + }, + "transposed_measures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Measure field names that have been transposed into rows." + }, + "userEditedSQL": { + "type": "string", + "description": "User-authored raw SQL (empty string when not in SQL mode)." + }, + "version": { + "type": "number", + "description": "Schema version for migration support." + } + }, + "required": [ + "calculations", + "column_totals", + "fields", + "fill_fields", + "filters", + "pivots", + "row_totals", + "sorts", + "table", + "userEditedSQL" + ], + "additionalProperties": {}, + "description": "The semantic query for this tab, minus the server-owned workbook model anchors (modelId / model_extension_id). Omitted on a no-op replay; the server anchors new/changed tiles to the draft." + }, + "resultConfig": { + "type": "object", + "additionalProperties": {}, + "description": "Result display configuration (column widths, frozen columns, conditional formatting, number formatting, etc.)." + }, + "subTitle": { + "type": [ + "string", + "null" + ], + "maxLength": 250, + "description": "User-provided tab subtitle." + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "The topic (explore) this query is built on." + }, + "type": { + "type": "string", + "enum": [ + "blank", + "csv", + "query", + "dataset", + "spreadsheet", + "sql", + "dbt", + "query-view", + "linked", + "app" + ], + "description": "The query presentation type (e.g. SEMANTIC, SQL, LINKED, SPREADSHEET)." + }, + "visConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "chartType": { + "type": [ + "string", + "null" + ], + "enum": [ + "auto", + "area", + "areaStacked", + "areaStackedPercentage", + "bar", + "barLine", + "barGrouped", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "regionMap", + "markdown", + "omni-ai-summary-markdown", + "pie", + "funnel", + "sankey", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "singleRecord", + "omni-spreadsheet", + "summaryValue", + "svgMap", + "table", + null + ], + "description": "High-level chart type (e.g. \"bar\", \"line\", \"area\")." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names used in the visualization axes/series." + }, + "version": { + "type": "number", + "description": "Schema version for vis config migration." + }, + "visConfig": { + "type": "object", + "properties": { + "visType": { + "type": [ + "string", + "null" + ], + "enum": [ + "vegalite", + "omni-ai-summary-markdown", + "basic", + "omni-kpi", + "map", + "omni-markdown", + "funnel", + "sankey", + "single-record", + "svg-map", + "omni-spreadsheet", + "spreadsheet-tab", + "summary-value", + "omni-table", + "app", + null + ], + "description": "The visualization type (e.g. \"basic\", \"omni-table\")." + } + }, + "additionalProperties": {}, + "description": "Inner visualization config — structure varies by visType." + } + }, + "additionalProperties": {}, + "description": "Visualization configuration for the tile." + }, + "sourceQueryPresentationKey": { + "type": [ + "string", + "null" + ], + "pattern": "^[1-9][0-9]*$", + "description": "For LINKED-type tabs, the record key — the same identifier used as a `queryPresentations.data` key — of the source tile whose query this tab reuses. Null for all other tab types. This is a tile record key, NOT a positional index into `order`." + } + }, + "required": [ + "type" + ], + "additionalProperties": false + }, + "SettingsPatchExternal": { + "type": "object", + "properties": { + "crossfilterEnabled": { + "type": "boolean", + "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." + }, + "customText": { + "type": [ + "object", + "null" + ], + "properties": { + "queryError": { + "type": "string", + "description": "Custom text shown when a query errors, replacing the default error text." + }, + "queryNoResults": { + "type": "string", + "description": "Custom text shown when a query returns no results, replacing the default empty state." + } + }, + "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." + }, + "facetFilters": { + "type": "boolean", + "description": "When true, dashboard filters are applied per-facet when faceting is active." + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds. Null disables auto-refresh." + }, + "runQueriesOn": { + "type": [ + "string", + "null" + ], + "enum": [ + "current-page", + "all-pages", + null + ], + "description": "Controls whether dashboard queries execute on the visible page or across all pages." + } + }, + "description": "Document settings. Shallow-merged with the existing settings." + }, + "DocumentsV2ReadResponse": { + "type": "object", + "properties": { + "containers": { + "$ref": "#/components/schemas/Containers" + }, + "controls": { + "$ref": "#/components/schemas/ControlsReadExternal" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "name": { + "type": "string", + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsReadExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsReadExternal" + } + }, + "required": [ + "description", + "name", + "queryPresentations" + ] + }, + "ControlsReadExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/ControlReadExternal" + }, + "description": "Controls keyed by control ID." + }, + "order": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Display order for controls." + } + }, + "required": [ + "data", + "order" + ] + }, + "ControlReadExternal": { + "type": "object", + "properties": { + "config": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ], + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.)." + }, + "map": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "boolean", + "enum": [ + false + ] + } + ] + }, + "description": "Per-tile field overrides keyed by tab ID. Values are a field name (override) or false (exclude tile from control)." + } + }, + "required": [ + "config" + ] + }, + "QueryPresentationsReadExternal": { + "type": "object", + "properties": { + "data": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/QueryPresentationReadExternal" + }, + "description": "Query presentations keyed by tab ID." + }, + "order": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[1-9][0-9]*$" + }, + "description": "Tab display order." + } + }, + "required": [ + "data", + "order" + ] + }, + "QueryPresentationReadExternal": { + "type": "object", + "properties": { + "aiConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "description": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + }, + "subTitle": { + "type": "object", + "properties": { + "aiContext": { + "type": "string" + }, + "enabled": { + "type": "boolean" + } + } + } + }, + "description": "AI-generated metadata config (subtitle/description auto-generation settings)." + }, + "automaticVis": { + "type": [ + "boolean", + "null" + ], + "description": "When true, the system automatically selects the best visualization type." + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "User-provided tab description." + }, + "editingModelObjectName": { + "type": [ + "string", + "null" + ], + "description": "Model object (view/topic) currently being edited via the dataset/query-view editor. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "editingModelObjectNameChange": { + "type": [ + "string", + "null" + ], + "description": "Pending rename of the model object being edited. Applies only to dataset / query-view tabs — omitted from reads and rejected on patches for other tab types." + }, + "filterOrder": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Ordered list of filter field names controlling display order on this tab." + }, + "isSql": { + "type": [ + "boolean", + "null" + ], + "description": "Whether this tab is in raw SQL mode." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 144, + "description": "User-provided tab name." + }, + "prefersChart": { + "type": "boolean", + "description": "When true, the chart view is shown by default instead of the data table." + }, + "query": { + "type": [ + "object", + "null" + ], + "properties": { + "aiGenerated": { + "type": "boolean", + "description": "True when AI generated this query’s SQL; the AI SQL is shown in the advanced SQL box." + }, + "branch_id": { + "type": "string", + "description": "Branch model ID when querying against a model branch." + }, + "calculations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "allow_refs_to_unselected_fields": { + "type": "boolean", + "description": "Set by the Kotlin parser when this calc references fields not selected at the top level (AI SQL-gen produces these; UI-authored calcs do not)." + }, + "calc_name": { + "type": "string", + "description": "Internal identifier for the calculation, used as the column alias." + }, + "description": { + "type": "string", + "description": "Description of the calculation." + }, + "format": { + "type": "string", + "description": "Number/date format string (e.g. \"#,##0.00\")." + }, + "label": { + "type": "string", + "description": "Display label shown in the UI." + }, + "original_formula": { + "type": "string", + "description": "The original Excel-style formula before parsing (e.g. \"=SUM(A1:A10)\")." + }, + "outside_pivot": { + "type": "boolean", + "description": "When true, the calculation is evaluated outside the pivot grouping." + }, + "pushdown": { + "type": [ + "boolean", + "null" + ], + "description": "Per-calc override for whether to evaluate before the row limit. `null` defers to the model-level default." + }, + "sql": { + "type": "string", + "description": "Compiled SQL string produced from the formula." + }, + "sql_expression": { + "description": "Parsed SQL expression tree (serialized)." + }, + "swallow_errors": { + "type": "boolean", + "description": "When true, calculation errors are silently swallowed instead of surfaced." + } + }, + "required": [ + "calc_name" + ], + "additionalProperties": {} + }, + "description": "Table calculations attached to this query." + }, + "column_limit": { + "type": "number", + "description": "Max number of pivot columns to return." + }, + "column_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Column-level aggregation totals, keyed by field name." + }, + "controls": { + "type": "array", + "items": { + "oneOf": [ + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "field": { + "type": "string" + }, + "kind": { + "type": "string", + "enum": [ + "FIELD", + "TIMEFRAME" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_SELECTION" + ] + } + }, + "required": [ + "id", + "field", + "kind", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "display": { + "type": "string", + "enum": [ + "SELECT", + "BUTTON_TOGGLE" + ] + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "selectionMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_SELECTION" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "id", + "options", + "selectionMap", + "type" + ] + }, + { + "type": "object", + "properties": { + "computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "filterId": { + "type": "string" + }, + "isDynamicPreviousPeriod": { + "type": "boolean" + }, + "periodsAgo": { + "type": [ + "number", + "null" + ] + }, + "timeUnitName": { + "type": [ + "string", + "null" + ] + } + }, + "required": [ + "periodsAgo", + "timeUnitName" + ] + } + }, + "filterFieldName": { + "type": "string" + }, + "filterId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "PERIOD_OVER_PERIOD" + ] + } + }, + "required": [ + "computations", + "filterFieldName", + "id", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "isDimension": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "topicLabel": { + "type": "string" + }, + "value": { + "type": "string" + }, + "viewLabel": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "FIELD_PICKER" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "options", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR" + ] + }, + "filters": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "filter": { + "$ref": "#/components/schemas/JsonValue" + }, + "id": { + "type": "string" + } + }, + "required": [ + "fieldName", + "filter", + "id" + ] + } + }, + "type": { + "type": "string", + "enum": [ + "MULTI_FIELD_FILTER" + ] + } + }, + "required": [ + "id", + "conjunction", + "filters", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "fieldSelection": { + "oneOf": [ + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "full-model" + ] + } + }, + "required": [ + "mode" + ] + }, + { + "type": "object", + "properties": { + "mode": { + "type": "string", + "enum": [ + "auto" + ] + }, + "topics": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "mode", + "topics" + ] + }, + { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fieldName": { + "type": "string" + }, + "topicName": { + "type": "string" + } + }, + "required": [ + "fieldName" + ] + } + }, + "mode": { + "type": "string", + "enum": [ + "specific" + ] + } + }, + "required": [ + "fields", + "mode" + ] + } + ] + }, + "includeViewNameInLabels": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "DYNAMIC_FILTER" + ] + } + }, + "required": [ + "id", + "fieldSelection", + "type" + ] + }, + { + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "hidden": { + "type": "boolean" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "defaultValue": { + "type": "integer", + "minimum": 1 + }, + "field": { + "type": "string" + }, + "max": { + "type": "integer", + "minimum": 1 + }, + "min": { + "type": "integer", + "minimum": 1 + }, + "type": { + "type": "string", + "enum": [ + "TOP_N" + ] + }, + "value": { + "type": "integer", + "minimum": 1 + } + }, + "required": [ + "id", + "defaultValue", + "field", + "type", + "value" + ] + } + ] + }, + "description": "Interactive controls (field selectors, PoP controls) attached to this query." + }, + "cube_metadata": { + "type": "object", + "properties": { + "cube_name": { + "type": "string" + }, + "hash_key": { + "type": "string" + }, + "topic_name": { + "type": "string" + } + }, + "required": [ + "cube_name", + "hash_key", + "topic_name" + ], + "additionalProperties": {}, + "description": "Cube-specific metadata (topic name, cube name, hash key) for cube-backed queries." + }, + "custom_summary_types": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Per-field custom summary functions (e.g. SUM, AVG, COUNT)." + }, + "dbtFileName": { + "type": "string", + "description": "dbt file name when this query is backed by a dbt model." + }, + "dbtMode": { + "type": "boolean", + "description": "Whether this query is in dbt mode." + }, + "default_group_by": { + "type": "boolean", + "description": "When true, all dimensions are implicitly included in GROUP BY." + }, + "dimensionIndex": { + "type": "number", + "description": "Index of the primary dimension used for result ordering." + }, + "executableSQL": { + "type": "string", + "description": "Server-compiled SQL string (read-only, set by the backend)." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Model field names selected for the query (dimensions + measures)." + }, + "fill_fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Fields whose missing date/time values should be filled with nulls to create continuous series." + }, + "filters": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Query filters keyed by filter ID." + }, + "filtersUsedInSql": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "case_insensitive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "CONTAINS", + "ENDS_WITH", + "STARTS_WITH", + "EQUALS", + "IS_EMPTY", + "SQL_LIKE" + ] + }, + "type": { + "type": "string", + "enum": [ + "string" + ] + }, + "values": { + "type": "array", + "items": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_inclusive": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "LESS_THAN", + "GREATER_THAN", + "EQUALS", + "BETWEEN" + ] + }, + "type": { + "type": "string", + "enum": [ + "number" + ] + }, + "values": { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type", + "values" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "isFiscal": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "kind": { + "type": "string", + "enum": [ + "IS_ON_DAY_OF_WEEK", + "IS_ON_DAY_OF_QUARTER", + "IS_IN_MONTH_OF_YEAR", + "IS_ON_DAY_OF_YEAR", + "IS_AT_HOUR_OF_DAY", + "IS_IN_QUARTER_OF_YEAR", + "IS_IN_WEEK_OF_YEAR", + "IS_ON_DAY_OF_MONTH", + "BETWEEN", + "ON_OR_AFTER", + "BEFORE", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "QUERY_OFFSET" + ] + }, + "left_side": { + "type": [ + "string", + "null" + ] + }, + "offset_interval_string": { + "type": [ + "string", + "null" + ] + }, + "right_side": { + "type": [ + "string", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "date" + ] + }, + "ui_type": { + "type": [ + "string", + "null" + ], + "enum": [ + "ANY_TIME", + "BEFORE", + "BETWEEN", + "MONTH_OF_YEAR", + "PAST", + "YEAR", + "DAY", + "IS_ON_DAY_OF_WEEK", + "ON_OR_AFTER", + "IS_IN_THE_MONTH", + "IS_IN_THE_QUARTER", + "IS_IN_THE_FISCAL_QUARTER", + "IS_IN_THE_FISCAL_YEAR", + "TIME_FOR_INTERVAL_DURATION", + "TIME_FOR_UNIT_DURATION", + "CUSTOM", + null + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "kind", + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "null" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "treat_nulls_as_false": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "boolean" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "disregard_limit": { + "type": "boolean" + }, + "field_name": { + "type": "string" + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "query_id": { + "type": "string" + }, + "type": { + "type": "string", + "enum": [ + "query" + ] + }, + "view_query": { + "type": "object", + "properties": { + "fields": { + "type": "array", + "items": { + "type": "string" + } + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "default": {} + }, + "limit": { + "type": "number" + }, + "sorts": { + "type": "array", + "items": {}, + "default": [] + }, + "table": { + "type": "string" + } + }, + "required": [ + "fields" + ], + "additionalProperties": {} + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "type": { + "type": "string", + "enum": [ + "user_attribute" + ] + }, + "user_attribute_name": { + "type": "string" + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "type", + "user_attribute_name" + ], + "additionalProperties": {} + }, + { + "type": "object", + "properties": { + "cancel_query_filter": { + "type": "boolean" + }, + "ignore_if_unjoinable": { + "type": "boolean" + }, + "conjunction": { + "type": "string", + "enum": [ + "OR", + "AND" + ] + }, + "filters": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CompositeFilter" + } + }, + "is_negative": { + "type": [ + "boolean", + "null" + ] + }, + "type": { + "type": "string", + "enum": [ + "composite" + ] + }, + "appliedLabels": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "base_view": { + "type": "string" + }, + "description": { + "type": "string" + }, + "fieldName": { + "type": "string" + }, + "filterControlType": { + "anyOf": [ + { + "type": "string", + "enum": [ + "multiValueEquals", + "singleValueEquals" + ] + }, + { + "type": "string", + "enum": [ + "singleDay", + "timeframe" + ] + } + ] + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "topic": { + "type": "string" + }, + "watchedContainerIds": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "conjunction", + "filters", + "type" + ], + "additionalProperties": {} + } + ] + }, + "description": "Filters that were embedded directly in raw SQL (read-only)." + }, + "join_paths_from_topic_name": { + "type": "string", + "description": "Topic name that determines join path precedence for parsed SQL queries." + }, + "join_via_map": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": { + "type": "string" + } + }, + "description": "Virtual topic join path overrides, keyed by view name to ordered join path." + }, + "limit": { + "type": "number", + "description": "Row limit for the query." + }, + "manualSort": { + "type": "boolean", + "description": "When true, the user has explicitly set a custom sort order." + }, + "metadata": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "format": { + "type": "string" + }, + "label": { + "type": "string" + }, + "order": { + "type": "number" + } + }, + "additionalProperties": {} + }, + "description": "Per-field display metadata (format, label, order)." + }, + "offset": { + "type": "number", + "description": "Row offset for pagination." + }, + "parsed": { + "type": "boolean", + "description": "Whether this raw SQL query has been parsed into a semantic query." + }, + "periodOverPeriodTransposed": { + "type": "boolean", + "description": "Whether the period-over-period comparison columns are transposed." + }, + "period_over_period_computations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date_filter_field_name": { + "type": "string", + "description": "The date dimension field this comparison is anchored to." + }, + "date_filter_id": { + "type": "string", + "description": "ID of the date filter being offset (if backed by a dashboard filter)." + }, + "is_dynamic_previous_period": { + "type": "boolean", + "description": "When true, the previous period is calculated dynamically relative to the current filter range." + }, + "periods_ago": { + "type": [ + "number", + "null" + ], + "description": "How many periods back to compare (e.g. 1 = previous period). Null if not set." + }, + "time_unit_name": { + "type": [ + "string", + "null" + ], + "description": "Time grain for the offset (e.g. \"month\", \"year\"). Null if not set." + } + }, + "required": [ + "date_filter_field_name", + "periods_ago", + "time_unit_name" + ], + "additionalProperties": {} + }, + "description": "Period-over-period comparison configurations." + }, + "pivots": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names to pivot on (columns become values)." + }, + "rewriteSql": { + "type": "boolean", + "description": "When true, the backend should rewrite/optimize the SQL." + }, + "row_totals": { + "type": "object", + "additionalProperties": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "aggregation" + ] + } + }, + "required": [ + "type" + ] + }, + "description": "Row-level aggregation totals, keyed by field name." + }, + "sorts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "column_name": { + "type": "string", + "description": "The model field name to sort by." + }, + "is_column_sort": { + "type": "boolean", + "description": "When true, this sort targets a pivoted column rather than a row dimension." + }, + "pivot_value_map": { + "type": "object", + "additionalProperties": { + "type": [ + "string", + "null" + ] + }, + "description": "Maps pivot field names to specific pivot values, scoping the sort to a single pivot column." + }, + "sort_descending": { + "type": "boolean", + "description": "When true, sort order is descending." + }, + "subtotal_sort": { + "type": "string", + "description": "Field name whose subtotal row should be used as the sort key." + } + }, + "required": [ + "column_name", + "sort_descending" + ], + "additionalProperties": {} + }, + "description": "Sort clauses applied to the query result set." + }, + "sqlSortsEnabled": { + "type": "boolean", + "description": "Whether user-created sorts are enabled on a raw SQL query." + }, + "staticQueryReferences": { + "type": "object", + "additionalProperties": {}, + "description": "Pre-computed query references for AI chat context. Inner shape is `OmniQuery & { model_id: string }`; left as `unknown` to avoid a recursive zod schema. Validated structurally by consumers when they execute the referenced sub-queries." + }, + "table": { + "type": "string", + "description": "Base view (table) name in the model." + }, + "transposed_measures": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Measure field names that have been transposed into rows." + }, + "userEditedSQL": { + "type": "string", + "description": "User-authored raw SQL (empty string when not in SQL mode)." + }, + "version": { + "type": "number", + "description": "Schema version for migration support." + } + }, + "required": [ + "calculations", + "column_totals", + "fields", + "fill_fields", + "filters", + "pivots", + "row_totals", + "sorts", + "table", + "userEditedSQL" + ], + "additionalProperties": {}, + "description": "The semantic query for this tab, minus the server-owned workbook model anchors (modelId / model_extension_id). For LINKED-type tabs this field is read-only." + }, + "resultConfig": { + "type": "object", + "additionalProperties": {}, + "description": "Result display configuration (column widths, frozen columns, conditional formatting, number formatting, etc.)." + }, + "subTitle": { + "type": [ + "string", + "null" + ], + "maxLength": 250, + "description": "User-provided tab subtitle." + }, + "topicName": { + "type": [ + "string", + "null" + ], + "description": "The topic (explore) this query is built on." + }, + "type": { + "type": "string", + "enum": [ + "blank", + "csv", + "query", + "dataset", + "spreadsheet", + "sql", + "dbt", + "query-view", + "linked", + "app" + ], + "description": "The query presentation type (e.g. SEMANTIC, SQL, LINKED, SPREADSHEET)." + }, + "visConfig": { + "type": [ + "object", + "null" + ], + "properties": { + "chartType": { + "type": [ + "string", + "null" + ], + "enum": [ + "auto", + "area", + "areaStacked", + "areaStackedPercentage", + "bar", + "barLine", + "barGrouped", + "barStacked", + "barStackedPercentage", + "boxplot", + "code", + "column", + "columnGrouped", + "columnStacked", + "columnStackedPercentage", + "heatmap", + "kpi", + "line", + "lineColor", + "map", + "regionMap", + "markdown", + "omni-ai-summary-markdown", + "pie", + "funnel", + "sankey", + "point", + "pointColor", + "pointSize", + "pointSizeColor", + "singleRecord", + "omni-spreadsheet", + "summaryValue", + "svgMap", + "table", + null + ], + "description": "High-level chart type (e.g. \"bar\", \"line\", \"area\")." + }, + "fields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Field names used in the visualization axes/series." + }, + "version": { + "type": "number", + "description": "Schema version for vis config migration." + }, + "visConfig": { + "type": "object", + "properties": { + "visType": { + "type": [ + "string", + "null" + ], + "enum": [ + "vegalite", + "omni-ai-summary-markdown", + "basic", + "omni-kpi", + "map", + "omni-markdown", + "funnel", + "sankey", + "single-record", + "svg-map", + "omni-spreadsheet", + "spreadsheet-tab", + "summary-value", + "omni-table", + "app", + null + ], + "description": "The visualization type (e.g. \"basic\", \"omni-table\")." + } + }, + "additionalProperties": {}, + "description": "Inner visualization config — structure varies by visType." + } + }, + "additionalProperties": {}, + "description": "Visualization configuration for the tile." + }, + "sourceQueryPresentationKey": { + "type": [ + "string", + "null" + ], + "pattern": "^[1-9][0-9]*$", + "description": "For LINKED-type tabs, the record key — the same identifier used as a `queryPresentations.data` key — of the source tile whose query this tab reuses. Null for all other tab types. This is a tile record key, NOT a positional index into `order`." + } + }, + "required": [ + "aiConfig", + "automaticVis", + "description", + "filterOrder", + "isSql", + "name", + "prefersChart", + "query", + "resultConfig", + "subTitle", + "topicName", + "type", + "visConfig", + "sourceQueryPresentationKey" + ] + }, + "SettingsReadExternal": { + "type": "object", + "properties": { + "crossfilterEnabled": { + "type": "boolean", + "description": "When true, clicking a value in one tile filters all other tiles on the dashboard." + }, + "customText": { + "type": [ + "object", + "null" + ], + "properties": { + "queryError": { + "type": "string", + "description": "Custom text shown when a query errors, replacing the default error text." + }, + "queryNoResults": { + "type": "string", + "description": "Custom text shown when a query returns no results, replacing the default empty state." + } + }, + "description": "Custom text replacing default UI strings on the dashboard, e.g. when queries error or return no results." + }, + "facetFilters": { + "type": "boolean", + "description": "When true, dashboard filters are applied per-facet when faceting is active." + }, + "refreshInterval": { + "type": [ + "number", + "null" + ], + "description": "Auto-refresh interval in seconds. Null disables auto-refresh." + }, + "runQueriesOn": { + "type": [ + "string", + "null" + ], + "enum": [ + "current-page", + "all-pages", + null + ], + "description": "Controls whether dashboard queries execute on the visible page or across all pages." + } + }, + "required": [ + "crossfilterEnabled", + "customText", + "facetFilters", + "refreshInterval", + "runQueriesOn" + ] + }, + "DocumentsV2PatchDraftResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "draftIdentifier": { + "type": "string", + "description": "Identifier of the draft the patch was applied to." + }, + "identifier": { + "type": "string", + "description": "Published document identifier the draft targets." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "draftIdentifier", + "identifier", + "name" + ] + }, + "DocumentsV2CreateDraftBody": { + "allOf": [ + { + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" + }, + { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "Branch the draft is created on. Omit for a draft on the main (unpublished) workspace." + } + }, + "additionalProperties": false + } + ] + }, + "DocumentsV2PatchDraftBody": { + "type": "object", + "properties": { + "containers": { + "allOf": [ + { + "$ref": "#/components/schemas/Containers" + }, + { + "description": "Container layout. When present, fully replaces the existing layout." + } + ] + }, + "controls": { + "$ref": "#/components/schemas/ControlsPatchExternal" + }, + "description": { + "type": [ + "string", + "null" + ] + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 254, + "description": "Document name." + }, + "queryPresentations": { + "$ref": "#/components/schemas/QueryPresentationsPatchExternal" + }, + "settings": { + "$ref": "#/components/schemas/SettingsPatchExternal" + }, + "summary": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Caller-supplied description of what this patch changes, written to the history audit trail. When absent, the server generates one from the touched sections." + } + }, + "additionalProperties": false + }, + "DocumentsV2PublishDraftResponse": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "description": "Document description." + }, + "identifier": { + "type": "string", + "description": "Published document identifier." + }, + "name": { + "type": "string", + "description": "Document name." + } + }, + "required": [ + "description", + "identifier", + "name" + ] + }, + "EmbedSsoGenerateSessionResponse": { + "type": "object", + "properties": { + "sessionId": { + "type": "string", + "description": "Session ID to use for embedding Omni content" + } + }, + "required": [ + "sessionId" + ] + }, + "EmbedSsoGenerateSessionBody": { + "type": "object", + "properties": { + "externalId": { + "type": "string", + "description": "External identifier for the user (from your system)", + "example": "user-123" + }, + "groups": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Optional list of group names to assign to the user", + "example": [ + "engineering", + "sales" + ] + }, + "name": { + "type": "string", + "description": "Display name for the user", + "example": "John Doe" + }, + "userAttributes": { + "type": "object", + "additionalProperties": {}, + "description": "Optional user attributes for row-level security" + } + }, + "required": [ + "externalId", + "name" + ] + }, + "EvalPromptSetsListResponse": { + "type": "object", + "properties": { + "prompt_sets": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalPromptSetListItem" + }, + "description": "Prompt sets matching the query, sorted alphabetically by name." + } + }, + "required": [ + "prompt_sets" + ] + }, + "EvalPromptSetListItem": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description of the prompt set.", + "example": "Regression suite for the orders topic" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the prompt set has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "description": "Human-readable name for the prompt set.", + "example": "Orders regression" + }, + "slug": { + "type": "string", + "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", + "example": "orders-regression" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was last updated.", + "example": "2025-01-15T10:00:00.000Z" + }, + "latest_run_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp of the most recent run on this prompt set, if any.", + "example": "2025-01-15T10:05:00.000Z" + }, + "prompt_count": { + "type": "integer", + "description": "Number of prompts in the set.", + "example": 12 + } + }, + "required": [ + "created_at", + "description", + "id", + "is_archived", + "model_id", + "name", + "slug", + "updated_at", + "latest_run_at", + "prompt_count" + ] + }, + "EvalApiError400": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Bad Request: name: Required" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 400 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError401": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Unauthorized: Missing or invalid API key" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 401 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError403": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "AI eval requires at least Querier access on the model" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 403 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalApiError404": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Prompt set not found" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 404 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsCreateResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSet": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description of the prompt set.", + "example": "Regression suite for the orders topic" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the prompt set has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "description": "Human-readable name for the prompt set.", + "example": "Orders regression" + }, + "prompts": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalPrompt" + }, + "description": "Prompts that make up the set." + }, + "slug": { + "type": "string", + "description": "URL-safe identifier for the prompt set. Unique per `model_id`.", + "example": "orders-regression" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt set was last updated.", + "example": "2025-01-15T10:00:00.000Z" + } + }, + "required": [ + "created_at", + "description", + "id", + "is_archived", + "model_id", + "name", + "prompts", + "slug", + "updated_at" + ] + }, + "EvalPrompt": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "expectation": { + "type": [ + "string", + "null" + ], + "description": "The expectation the analysis judge scores the analysis against, or null when none was set.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the prompt.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "prompt_text": { + "type": "string", + "description": "The natural language prompt text the AI is evaluated on.", + "example": "What are the top 5 products by revenue?" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the prompt was last updated.", + "example": "2025-01-15T10:00:00.000Z" + } + }, + "required": [ + "created_at", + "expectation", + "id", + "prompt_text", + "updated_at" + ] + }, + "EvalPromptSetsCreateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "Optional human-readable description of the prompt set. Max 1024 characters.", + "example": "Regression suite for the orders topic" + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this prompt set is bound to.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "Human-readable name for the prompt set. 255 characters or fewer.", + "example": "Orders regression" + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expectation": { + "type": [ + "string", + "null" + ], + "maxLength": 16000, + "description": "Optional expectation the analysis judge scores the analysis against. Max 16000 characters.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "prompt_text": { + "type": "string", + "minLength": 1, + "maxLength": 8000, + "description": "The natural language prompt text. Max 8000 characters.", + "example": "What are the top 5 products by revenue?" + } + }, + "required": [ + "prompt_text" + ] + }, + "maxItems": 25, + "default": [], + "description": "Initial prompts for the set. Defaults to an empty list. At most 25 prompts." + }, + "slug": { + "type": "string", + "maxLength": 255, + "pattern": "^[a-z][a-z0-9-]*$", + "description": "URL-safe identifier for the prompt set. Must be unique per `model_id` and match `^[a-z][a-z0-9-]*$`. Max 255 characters.", + "example": "orders-regression" + } + }, + "required": [ + "model_id", + "name", + "slug" + ] + }, + "EvalPromptSetsGetResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalPromptSetsUpdateResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "EvalApiError422": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "A prompt being updated does not belong to this prompt set" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 422 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsUpdateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 1024, + "description": "New description for the prompt set. Pass `null` to clear. Max 1024 characters." + }, + "name": { + "type": "string", + "minLength": 1, + "maxLength": 255, + "description": "New human-readable name for the prompt set. 255 characters or fewer." + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "expectation": { + "type": [ + "string", + "null" + ], + "maxLength": 16000, + "description": "Optional expectation the analysis judge scores the analysis against. Pass `null` to clear. Max 16000 characters.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Existing prompt id. When provided, updates that prompt; when omitted, a new prompt is created. Prompts not included in this list are removed." + }, + "prompt_text": { + "type": "string", + "minLength": 1, + "maxLength": 8000, + "description": "Updated or new prompt text. Max 8000 characters.", + "example": "What are the top 10 products by revenue this quarter?" + } + }, + "required": [ + "prompt_text" + ] + }, + "maxItems": 25, + "description": "Full desired set of prompts after the update. Prompts omitted from this list are deleted; new prompts (no `id`) are appended in body order. Existing prompts retain their original position — reordering is not supported on this endpoint. At most 25 prompts total." + } + } + }, + "EvalPromptSetsDeleteResponse": { + "type": "object", + "properties": { + "cancelled_job_count": { + "type": "integer", + "description": "Number of in-flight agentic jobs associated with this prompt set that were cancelled as part of the archive.", + "example": 0 + }, + "is_archived": { + "type": "boolean", + "enum": [ + true + ], + "description": "Always `true` on success — archives the prompt set." + } + }, + "required": [ + "cancelled_job_count", + "is_archived" + ] + }, + "EvalApiError500": { + "type": "object", + "properties": { + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Archive committed but a run-cancellation failed; retry to complete" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 500 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalPromptSetsUnarchiveResponse": { + "type": "object", + "properties": { + "prompt_set": { + "$ref": "#/components/schemas/EvalPromptSet" + } + }, + "required": [ + "prompt_set" + ] + }, + "FoldersListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents in the folder" + }, + "favorites": { + "type": "number", + "description": "Number of users who have favorited this folder" + } + }, + "required": [ + "documents", + "favorites" + ], + "description": "Count statistics for the folder" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique folder identifier" + }, + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels associated with the folder" + }, + "name": { + "type": "string", + "description": "Name of the folder", + "example": "My Reports" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" + }, + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "/shared/reports/my-reports" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/my-reports" + } + }, + "required": [ + "id", + "name", + "ownerId", + "path", + "url" + ] + }, + "description": "List of folders" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "FoldersCreateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the created folder" + }, + "name": { + "type": "string", + "description": "Name of the created folder" + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" + }, + "path": { + "type": "string", + "description": "Full path to the folder" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope of the folder" + } + }, + "required": [ + "id", + "name", + "ownerId", + "path", + "scope" + ] + }, + "FoldersCreateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "Name of the folder to create", + "example": "My New Folder" + }, + "parentFolderId": { + "type": "string", + "format": "uuid", + "description": "Parent folder ID (omit to create at root level)" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope for the folder" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to create the folder as (for org-scoped API keys only)" + } + }, + "required": [ + "name" + ] + }, + "FoldersDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the folder was deleted successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersUpdateResponse": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Folder ID" + }, + "name": { + "type": "string", + "description": "Updated folder name" + }, + "path": { + "type": "string", + "description": "Updated URL path segment for the folder (the folder's own segment only)" + } + }, + "required": [ + "id", + "name", + "path" + ] + }, + "FoldersUpdateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "New display name for the folder", + "example": "Q1 Reports" + }, + "path": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z0-9-]+$", + "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", + "example": "q1-reports" + }, + "resolvePathConflict": { + "type": "boolean", + "default": false, + "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." + } + } + }, + "FoldersGetPermissionsResponse": { + "type": "object", + "properties": { + "permits": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Whether access boost is enabled for this permit" + }, + "role": { + "type": "string", + "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", + "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "User group ID if this is a group permit" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID if this is a user permit" + } + }, + "required": [ + "role" + ] + }, + "description": "List of permission permits for the folder" + } + }, + "required": [ + "permits" + ] + }, + "FoldersAddPermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were added successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersAddPermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "default": false, + "description": "Whether to grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", + "example": "VIEWER" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to grant permission to" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to grant permission to" + } + }, + "required": [ + "role" + ], + "additionalProperties": false + }, + "FoldersUpdatePermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were updated successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersUpdatePermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "description": "Whether to grant access boost" + }, + "role": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "New content role to assign" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to update permissions for" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to update permissions for" + } + }, + "additionalProperties": false + }, + "FoldersRevokePermissionsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the permissions were revoked successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersRevokePermissionsBody": { + "type": "object", + "properties": { + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to revoke permissions from" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to revoke permissions from" + } + }, + "additionalProperties": false + }, + "LabelsListResponse": { + "type": "object", + "properties": { + "labels": { + "type": "array", + "items": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "description": "List of labels" + } + }, + "required": [ + "labels" + ] + }, + "LabelsCreateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsCreateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "default": null, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "default": null, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "default": false, + "description": "Show label on homepage. Requires admin permissions." + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "default": false, + "description": "Mark as verified label. Requires admin permissions." + } + }, + "required": [ + "name" + ] + }, + "LabelsGetResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" + }, + "name": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" + }, + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" + }, + "homepage": { + "type": "boolean", + "description": "Show label on homepage. Requires admin permissions to modify." + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "description": "Mark as verified label. Requires admin permissions to modify." + } + } + }, + "ModelsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseModelId": { + "type": [ + "string", + "null" + ], + "description": "Base model ID for branch/extension models" + }, + "branches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Branch ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ] + }, + "description": "Active branches (if include=activeBranches)" + }, + "connectionId": { + "type": [ + "string", + "null" + ], + "description": "Connection ID" + }, + "createdAt": { + "type": "string", + "description": "Creation timestamp" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Deletion timestamp" + }, + "id": { + "type": "string", + "description": "Model ID" + }, + "modelKind": { + "type": [ + "string", + "null" + ], + "description": "Model kind" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Model name" + }, + "updatedAt": { + "type": "string", + "description": "Last update timestamp" + } + }, + "required": [ + "baseModelId", + "connectionId", + "createdAt", + "deletedAt", + "id", + "modelKind", + "name", + "updatedAt" + ] + }, + "description": "List of model records" + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "CreateModelSchemaBase": { + "type": "object", + "properties": { + "accessGrants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoostable": { + "type": "boolean" + }, + "allowedValues": { + "type": "array", + "items": { + "type": "string" + } + }, + "codeComments": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "ignored": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "userAttribute": { + "type": "string" + } + }, + "required": [ + "accessBoostable", + "name" + ] + }, + "description": "Access grants for the model" + }, + "allowAsWorkbookBase": { + "type": "boolean", + "description": "Allow this model as a workbook base" + }, + "baseModelId": { + "type": "string", + "description": "Base model ID for extension or branch models" + }, + "connectionId": { + "type": "string", + "description": "Connection ID for the model" + }, + "modelKind": { + "anyOf": [ + { + "type": "string", + "enum": [ + "SCHEMA" + ] + }, + { + "type": "string", + "enum": [ + "SHARED" + ] + }, + { + "type": "string", + "enum": [ + "SHARED_EXTENSION" + ] + }, + { + "type": "string", + "enum": [ + "BRANCH" + ] + } + ], + "default": "SCHEMA", + "description": "Kind of model to create" + }, + "modelName": { + "type": "string", + "description": "Name for the model" + }, + "usesIsolatedBranches": { + "type": "boolean", + "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" + } + }, + "required": [ + "connectionId" + ] + }, + "ModelsUpdateResponse": { + "type": "object", + "properties": { + "model": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Model ID" + }, + "name": { + "type": "string", + "description": "Updated model name" + } + }, + "required": [ + "id", + "name" + ], + "description": "Updated model details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "model", + "success" + ] + }, + "ModelsUpdateBody": { + "type": "object", + "properties": { + "name": { + "type": "string", + "minLength": 1, + "description": "New name for the model", + "example": "My Renamed Model" + } + }, + "required": [ + "name" + ] + }, + "JobsGetStatusResponse": { + "type": "object", + "properties": { + "job_id": { + "type": "string", + "description": "The job ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "job_type": { + "type": "string", + "description": "The type of job (e.g., REFRESH_SCHEMA)", + "example": "REFRESH_SCHEMA" + }, + "status": { + "type": "string", + "enum": [ + "IN_PROGRESS", + "COMPLETED", + "FAILED" + ], + "description": "Current status of the job", + "example": "COMPLETED" + } + }, + "required": [ + "job_id", + "job_type", + "status" + ] + }, + "ModelsGetSchemasResponse": { + "type": "object", + "properties": { + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" + } + }, + "required": [ + "schemas" + ] + }, + "ModelsGetViewResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "View description" + }, + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Field name" + }, + "type": { + "type": "string", + "enum": [ + "dimension", + "measure", + "filter" + ], + "description": "Field type" + } + }, + "required": [ + "name", + "type" + ] + }, + "description": "Fields in the view" + }, + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { + "type": "string", + "description": "View label" + }, + "name": { + "type": "string", + "description": "View name" + } + }, + "required": [ + "fields", + "name" + ] + }, + "description": "List of views" + } + }, + "required": [ + "success", + "views" + ] + }, + "ModelsUpdateViewBody": { + "type": "object", + "properties": { + "aiContext": { + "type": "string", + "description": "AI context for the view" + }, + "description": { + "type": "string", + "description": "View description" + }, + "format": { + "type": "string", + "description": "View format" + }, + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { + "type": "string", + "description": "View label" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the view" + } + } + }, + "ModelsUpdateFieldBody": { + "type": "object", + "properties": { + "aiContext": { + "type": "string", + "description": "AI context for the field" + }, + "allValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Deprecated: use sampleValues instead" + }, + "binBoundaries": { + "type": "array", + "items": { + "type": "number" + }, + "description": "Bin boundaries for binned fields" + }, + "binLabels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels for bins" + }, + "description": { + "type": "string", + "description": "Field description" + }, + "drillFields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Drill-down fields" + }, + "elseValue": { + "type": "string", + "description": "Else value for grouped fields" + }, + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filters for the field" + }, + "format": { + "type": "string", + "description": "Field format" + }, + "groupFilters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Group filters" + }, + "groupLabel": { + "type": "string", + "description": "Group label" + }, + "groupNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Group names" + }, + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" + }, + "ignored": { + "type": "boolean", + "description": "Whether the field is ignored" + }, + "isCalc": { + "type": "boolean", + "description": "Whether this is a calculation field" + }, + "label": { + "type": "string", + "description": "Field label" + }, + "newFieldName": { + "type": "string", + "description": "New field name (for rename)" + }, + "newViewName": { + "type": "string", + "description": "New view name (for move)" + }, + "sampleValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sample values for the field" + }, + "sql": { + "type": "string", + "description": "SQL expression for the field" + }, + "synonyms": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Synonyms for the field" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for the field" + } + } + }, + "ModelsListTopicsResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topics": { + "type": "array", + "items": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + } + }, + "required": [ + "base_view_name", + "name" + ] + }, + "description": "List of topics" + } + }, + "required": [ + "success", + "topics" + ] + }, + "ModelsGetTopicResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topic": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + }, + "relationships": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Relationships for the topic" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Views available in the topic" + } + }, + "required": [ + "base_view_name", + "name", + "relationships", + "views" + ], + "description": "Topic details with relationships and views" + } + }, + "required": [ + "success", + "topic" + ] + }, + "ModelsUpdateTopicBody": { + "type": "object", + "properties": { + "description": { + "type": "string", + "description": "Topic description" + }, + "groupLabel": { + "type": "string", + "description": "Group label for the topic" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "newTopicName": { + "type": "string", + "description": "New topic name (for rename)" + } + } + }, + "ModelsCreateFieldBody": { + "type": "object", + "properties": { + "aggregateType": { + "type": "string", + "enum": [ + "AVERAGE", + "COUNT", + "COUNT_DISTINCT", + "LIST", + "MAX", + "MIN", + "SUM", + "MEDIAN", + "PERCENTILE", + "AVERAGE_DISTINCT_ON", + "SUM_DISTINCT_ON", + "MEDIAN_DISTINCT_ON", + "PERCENTILE_DISTINCT_ON", + "SEMANTIC_VIEW_AGG" + ], + "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", + "example": "SUM" + }, + "aiContext": { + "type": "string", + "description": "AI context for the field" + }, + "description": { + "type": "string", + "description": "Field description" + }, + "fieldName": { + "type": "string", + "description": "Field name", + "example": "total_revenue" + }, + "format": { + "type": "string", + "description": "Field format" + }, + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" + }, + "label": { + "type": "string", + "description": "Field label" + }, + "sql": { + "type": "string", + "description": "SQL expression for the field" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for topic-scoped fields" + }, + "viewName": { + "type": "string", + "description": "View to add the field to", + "example": "orders" + } + }, + "required": [ + "fieldName", + "viewName" + ], + "additionalProperties": false + }, + "ModelsRefreshResponse": { + "type": "object", + "properties": { + "jobId": { + "type": "string", + "description": "Job ID for the refresh operation" + }, + "modelId": { + "type": "string", + "description": "Model ID being refreshed" + }, + "status": { + "type": "string", + "enum": [ + "running", + "completed", + "failed" + ], + "description": "Current status of the refresh" + } + }, + "required": [ + "jobId", + "modelId", + "status" + ] + }, + "ModelsValidateResponse": { + "type": "object", + "properties": { + "issues": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field name with the issue" + }, + "message": { + "type": "string", + "description": "Validation issue message" + }, + "severity": { + "type": "string", + "enum": [ + "error", + "warning" + ], + "description": "Issue severity" + }, + "view": { + "type": "string", + "description": "View name with the issue" + } + }, + "required": [ + "message", + "severity" + ] + }, + "description": "List of validation issues" + }, + "valid": { + "type": "boolean", + "description": "Whether the model is valid" + } + }, + "required": [ + "issues", + "valid" + ] + }, + "ModelsMigrateBody": { + "type": "object", + "properties": { + "branchName": { + "type": "string", + "description": "Branch name for the target model" + }, + "commitMessage": { + "type": "string", + "description": "Commit message for git sync" + }, + "deleteViewsAndTopicsMissingFromSource": { + "type": "boolean", + "default": true, + "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead — useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." + }, + "gitRef": { + "type": "string", + "description": "Git reference" + }, + "targetModelId": { + "type": "string", + "format": "uuid", + "description": "Target model ID to migrate to" + } + }, + "required": [ + "targetModelId" + ] + }, + "ModelsDbtExposuresResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtExposureWithMeta" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "DbtExposureWithMeta": { + "type": "object", + "properties": { + "dashboard_identifier": { + "type": "string", + "description": "Identifier of the dashboard that generated this exposure" + }, + "deduplication_name": { + "type": "string", + "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." + }, + "exposure": { + "$ref": "#/components/schemas/DbtExposure" + } + }, + "required": [ + "dashboard_identifier", + "deduplication_name", + "exposure" + ] + }, + "DbtExposure": { + "type": "object", + "properties": { + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of dbt model references (e.g. ref('model_name'))", + "example": [ + "ref('orders')", + "ref('customers')" + ] + }, + "label": { + "type": "string", + "description": "Original dashboard name" + }, + "name": { + "type": "string", + "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", + "example": "my_dashboard" + }, + "owner": { + "$ref": "#/components/schemas/DbtExposureOwner" + }, + "type": { + "type": "string", + "enum": [ + "dashboard", + "notebook", + "analysis", + "ml", + "application" + ], + "description": "Type of the exposure", + "example": "dashboard" + }, + "url": { + "type": "string", + "description": "URL of the dashboard" + } + }, + "required": [ + "depends_on", + "name", + "owner", + "type" + ], + "description": "The dbt exposure for this dashboard." + }, + "DbtExposureOwner": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "Email of the dashboard owner" + }, + "name": { + "type": "string", + "description": "Name of the dashboard owner" + } + }, + "required": [ + "email", + "name" + ] + }, + "ModelsBranchDbtBody": { + "type": "object", + "properties": { + "dbt_environment_id": { + "type": "string", + "format": "uuid", + "description": "ID of the dbt environment to activate on this branch", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "dbt_git_branch": { + "type": "string", + "description": "Git branch to associate with the dbt environment", + "example": "feature/new-metrics" + } + }, + "required": [ + "dbt_environment_id" + ] + }, + "ModelsMergeBranchResponse": { + "type": "object", + "properties": { + "failed_drafts_count": { + "type": "number", + "description": "Number of drafts that failed to publish" + }, + "git_synced": { + "type": "boolean", + "description": "Whether git was synced" + }, + "published_drafts_count": { + "type": "number", + "description": "Number of drafts published" + }, + "success": { + "type": "boolean", + "description": "Whether the merge succeeded" + } + }, + "required": [ + "failed_drafts_count", + "git_synced", + "published_drafts_count", + "success" + ] + }, + "ModelsMergeBranchBody": { + "type": "object", + "properties": { + "commit_message": { + "type": "string", + "description": "Custom commit message for git sync" + }, + "delete_branch": { + "type": "boolean", + "default": false, + "description": "Delete the branch after merging" + }, + "force_override_git_settings": { + "type": "boolean", + "default": false, + "description": "Override PR-required or git-follower settings" + }, + "publish_drafts": { + "type": "boolean", + "default": true, + "description": "Publish branch-attached drafts" + } + } + }, + "ModelsCommitResponse": { + "type": "object", + "properties": { + "did_sync": { + "type": "boolean", + "description": "Whether a sync operation was performed against git" + }, + "git_sha": { + "type": [ + "string", + "null" + ], + "description": "The git SHA of the commit that was pushed (null if no commit was needed)" + }, + "in_sync": { + "type": "boolean", + "description": "Whether the branch is in sync with git after the operation" + }, + "pr_url": { + "type": [ + "string", + "null" + ], + "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." + } + }, + "required": [ + "did_sync", + "git_sha", + "in_sync", + "pr_url" + ] + }, + "ModelsCommitBody": { + "type": "object", + "properties": { + "allow_branch_exists": { + "type": "boolean", + "default": true, + "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", + "example": true + }, + "branch_id": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to commit.", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "commit_message": { + "type": "string", + "minLength": 1, + "description": "Commit message for the git commit.", + "example": "Add new orders view" + }, + "require_branch_exists": { + "type": "boolean", + "default": false, + "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", + "example": false + } + }, + "required": [ + "branch_id", + "commit_message" + ] + }, + "ModelsCacheResetResponse": { + "type": "object", + "properties": { + "cache_reset": { + "type": "object", + "properties": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "Creation timestamp" + }, + "model_id": { + "type": "string", + "description": "Model ID" + }, + "policy_name": { + "type": "string", + "description": "Cache policy name" + }, + "reset_at": { + "type": [ + "string", + "null" + ], + "description": "Reset timestamp" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "Last update timestamp" + } + }, + "required": [ + "created_at", + "model_id", + "policy_name", + "reset_at", + "updated_at" + ], + "description": "Cache reset details" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + } + }, + "required": [ + "cache_reset", + "success" + ] + }, + "ModelsCacheResetBody": { + "type": "object", + "properties": { + "resetAt": { + "type": "string", + "description": "ISO-8601 timestamp for when to reset the cache", + "example": "2024-01-15T12:00:00Z" + } + } + }, + "ModelsGitGetResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" + }, + "baseBranch": { + "type": "string", + "description": "The target branch for Omni pull requests", + "example": "main" + }, + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { "type": "string", "description": "Clone URL of the git repository (SSH or HTTPS)", "example": "git@github.com:org/repo.git" @@ -5482,6 +27259,11 @@ "type": "string", "description": "Optional branch ID" }, + "creator_id": { + "type": "string", + "format": "uuid", + "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." + }, "find": { "type": "string", "minLength": 1, @@ -5580,7 +27362,7 @@ "extension", "staged", "merged", - "history" + "fully-resolved" ], "default": "combined", "description": "IDE mode for YAML operations" @@ -5613,6 +27395,50 @@ ], "additionalProperties": false }, + "AiAgentActionsResponse": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AiAgentAction" + }, + "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." + } + }, + "required": [ + "records" + ] + }, + "AiAgentAction": { + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": [ + "sample", + "skill" + ], + "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", + "example": "skill" + }, + "label": { + "type": "string", + "description": "Short, human-readable name for the action — chip text in client UIs and the visible \"prompt\" on the answer card.", + "example": "Revenue trends" + }, + "prompt": { + "type": "string", + "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", + "example": "Skill:\nShow me the recent revenue trends grouped by month…" + } + }, + "required": [ + "kind", + "label", + "prompt" + ] + }, "QueryRunResponse": { "type": "object", "properties": { @@ -5710,7 +27536,7 @@ "userId": { "type": "string", "format": "uuid", - "description": "User ID to execute the query as (for row-level security). Only valid for org-scoped API keys.", + "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter — this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", "example": "550e8400-e29b-41d4-a716-446655440000" } } @@ -5926,7 +27752,7 @@ "example": false }, "filterConfig": { - "description": "Applied dashboard filter configuration" + "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." }, "id": { "type": "string", @@ -6632,6 +28458,76 @@ { "type": "object", "properties": { + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, "active": { "type": "boolean" }, @@ -7223,232 +29119,612 @@ } }, "required": [ - "records" + "records" + ] + }, + "UploadsListResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Upload" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Upload": { + "type": "object", + "properties": { + "connection_id": { + "type": "string", + "format": "uuid", + "description": "Connection ID the upload is associated with" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "When the file was uploaded" + }, + "file_name": { + "type": "string", + "description": "Original file name", + "example": "users.csv" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" + }, + "in_db_as_table_name": { + "type": [ + "string", + "null" + ], + "description": "Database table name if uploaded to database scratch schema" + }, + "model_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" + }, + "size_bytes": { + "type": [ + "number", + "null" + ], + "description": "File size in bytes" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" + }, + "uploaded_by_user": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "User ID of the uploader" + }, + "name": { + "type": "string", + "description": "Name of the user who uploaded the file" + } + }, + "required": [ + "id", + "name" + ], + "description": "User who uploaded the file" + }, + "view_name": { + "type": "string", + "description": "View name associated with the upload" + } + }, + "required": [ + "connection_id", + "created_at", + "file_name", + "id", + "in_db_as_table_name", + "model_id", + "size_bytes", + "updated_at", + "uploaded_by_user", + "view_name" + ] + }, + "UploadCreateResponse": { + "type": "object", + "properties": { + "fileName": { + "type": "string", + "description": "Original file name", + "example": "users.csv" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" + }, + "inDbAsTableName": { + "type": "string", + "description": "Database table name in the scratch schema" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID the view was created in" + }, + "rowCount": { + "type": "integer", + "description": "Number of rows in the uploaded file" + }, + "truncated": { + "type": "boolean", + "description": "Whether the file was truncated due to row limit" + }, + "viewCreated": { + "type": "boolean", + "description": "Whether a view was created in the model" + }, + "viewName": { + "type": "string", + "description": "Name of the view created" + } + }, + "required": [ + "fileName", + "id", + "inDbAsTableName", + "modelId", + "rowCount", + "truncated", + "viewCreated", + "viewName" + ] + }, + "UploadCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" + }, + "branchName": { + "type": "string", + "description": "Name of the branch to create the view in (mutually exclusive with branchId)" + }, + "file": { + "type": "string", + "description": "The CSV file to upload", + "format": "binary" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "UUID of the model to create the view in" + }, + "viewName": { + "type": "string", + "description": "Override the view name (defaults to sanitized file name)" + } + }, + "required": [ + "file", + "modelId" + ] + }, + "UploadDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the deletion was successful" + } + }, + "required": [ + "success" ] }, - "UploadsListResponse": { + "UsersGetModelRolesResponse": { "type": "object", "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" }, - "records": { + "results": { "type": "array", "items": { - "$ref": "#/components/schemas/Upload" - } + "$ref": "#/components/schemas/RoleAssignmentResult" + }, + "description": "List of role assignments" } }, "required": [ - "pageInfo", - "records" + "membershipId", + "results" ] }, - "Upload": { + "RoleAssignmentResult": { "type": "object", "properties": { - "connection_id": { + "baseRole": { "type": "string", - "format": "uuid", - "description": "Connection ID the upload is associated with" + "description": "The base role definition name", + "example": "VIEWER" }, - "created_at": { + "connectionId": { "type": "string", - "format": "date-time", - "description": "When the file was uploaded" + "format": "uuid", + "description": "Connection this role applies to" }, - "file_name": { - "type": "string", - "description": "Original file name", - "example": "users.csv" + "from": { + "$ref": "#/components/schemas/RoleOrigin" }, - "id": { + "modelId": { "type": "string", "format": "uuid", - "description": "Unique identifier for the upload" - }, - "in_db_as_table_name": { - "type": [ - "string", - "null" - ], - "description": "Database table name if uploaded to database scratch schema" + "description": "Model this role applies to" }, - "model_id": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" }, - "size_bytes": { - "type": [ - "number", - "null" - ], - "description": "File size in bytes" + "resolved": { + "type": "boolean", + "description": "Whether this is the resolved (effective) role" }, - "updated_at": { + "roleName": { "type": "string", - "format": "date-time", - "description": "Last update timestamp" + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "resolved", + "roleName" + ] + }, + "RoleOrigin": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "USER" + ], + "description": "Role assigned directly to user" + } + }, + "required": [ + "type" + ] }, - "uploaded_by_user": { - "type": [ - "object", - "null" - ], + { + "type": "object", "properties": { - "id": { + "type": { "type": "string", - "format": "uuid", - "description": "User ID of the uploader" + "enum": [ + "ORG" + ], + "description": "Role inherited from organization" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "BASE" + ], + "description": "Connection base role" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" }, "name": { "type": "string", - "description": "Name of the user who uploaded the file" + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role inherited from group membership" } }, "required": [ - "id", - "name" - ], - "description": "User who uploaded the file" + "depth", + "miniUuid", + "name", + "type" + ] + } + ], + "description": "Origin of this role assignment" + }, + "UsersAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" }, - "view_name": { + "membershipId": { "type": "string", - "description": "View name associated with the upload" + "format": "uuid", + "description": "The user membership ID" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" + }, + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + } + }, + "required": [ + "connectionId", + "membershipId", + "modelId", + "roleName" + ] + }, + "UsersAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" + } + }, + "required": [ + "roleName" + ] + }, + "UsersListEmailOnlyResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "User email address", + "example": "user@example.com" + }, + "user_attributes": { + "type": "object", + "additionalProperties": {}, + "description": "User attributes as key-value pairs" + }, + "user_id": { + "type": "string", + "format": "uuid", + "description": "User ID" + } + }, + "required": [ + "email", + "user_attributes", + "user_id" + ] + } } }, "required": [ - "connection_id", - "created_at", - "file_name", - "id", - "in_db_as_table_name", - "model_id", - "size_bytes", - "updated_at", - "uploaded_by_user", - "view_name" + "pageInfo", + "records" ] }, - "UploadCreateResponse": { + "UsersCreateEmailOnlyResponse": { "type": "object", "properties": { - "fileName": { - "type": "string", - "description": "Original file name", - "example": "users.csv" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the upload" - }, - "inDbAsTableName": { + "email": { "type": "string", - "description": "Database table name in the scratch schema" + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" }, - "modelId": { + "userId": { "type": "string", "format": "uuid", - "description": "Model ID the view was created in" - }, - "rowCount": { - "type": "integer", - "description": "Number of rows in the uploaded file" - }, - "truncated": { - "type": "boolean", - "description": "Whether the file was truncated due to row limit" - }, - "viewCreated": { - "type": "boolean", - "description": "Whether a view was created in the model" - }, - "viewName": { - "type": "string", - "description": "Name of the view created" + "description": "ID of the created user" } }, "required": [ - "fileName", - "id", - "inDbAsTableName", - "modelId", - "rowCount", - "truncated", - "viewCreated", - "viewName" + "email", + "userId" ] }, - "UploadCreateBody": { + "UsersCreateEmailOnlyBody": { "type": "object", "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" - }, - "branchName": { - "type": "string", - "description": "Name of the branch to create the view in (mutually exclusive with branchId)" - }, - "file": { - "type": "string", - "description": "The CSV file to upload", - "format": "binary" - }, - "modelId": { + "email": { "type": "string", - "format": "uuid", - "description": "UUID of the model to create the view in" + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" }, - "viewName": { - "type": "string", - "description": "Override the view name (defaults to sanitized file name)" + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" } }, "required": [ - "modelId" + "email" ] }, - "UploadDeleteResponse": { + "UsersCreateEmailOnlyBulkResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the deletion was successful" + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "description": "Results for each created user" } }, "required": [ - "success" + "results" ] }, - "UsersGetModelRolesResponse": { + "UsersCreateEmailOnlyBulkBody": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "minItems": 1, + "maxItems": 20, + "description": "Array of users to create (1-20 users)" + } + }, + "required": [ + "users" + ] + }, + "UserGroupsGetModelRolesResponse": { "type": "object", "properties": { - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" - }, "results": { "type": "array", "items": { - "$ref": "#/components/schemas/RoleAssignmentResult" + "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" }, "description": "List of role assignments" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" } }, "required": [ - "membershipId", - "results" + "results", + "userGroupId" ] }, - "RoleAssignmentResult": { + "UserGroupRoleAssignmentResult": { "type": "object", "properties": { "baseRole": { @@ -7462,7 +29738,7 @@ "description": "Connection this role applies to" }, "from": { - "$ref": "#/components/schemas/RoleOrigin" + "$ref": "#/components/schemas/UserGroupRoleOrigin" }, "modelId": { "type": "string", @@ -7473,109 +29749,55 @@ "type": "number", "description": "Priority for role resolution (higher = more permissive)" }, - "resolved": { - "type": "boolean", - "description": "Whether this is the resolved (effective) role" - }, "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" - } - }, - "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "resolved", - "roleName" - ] - }, - "RoleOrigin": { - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "USER" - ], - "description": "Role assigned directly to user" - } - }, - "required": [ - "type" - ] + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "roleName" + ] + }, + "UserGroupRoleOrigin": { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group (0 for direct assignment)" }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "ORG" - ], - "description": "Role inherited from organization" - } - }, - "required": [ - "type" - ] + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "BASE" - ], - "description": "Connection base role" - } - }, - "required": [ - "type" - ] + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" }, - { - "type": "object", - "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { - "type": "string", - "description": "Name of the group", - "example": "Engineering Team" - }, - "type": { - "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role inherited from group membership" - } - }, - "required": [ - "depth", - "miniUuid", - "name", - "type" - ] + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role assigned to group" } + }, + "required": [ + "depth", + "miniUuid", + "name", + "type" ], "description": "Origin of this role assignment" }, - "UsersAssignModelRoleResponse": { + "UserGroupsAssignModelRoleResponse": { "type": "object", "properties": { "connectionId": { @@ -7583,11 +29805,6 @@ "format": "uuid", "description": "The connection ID for this role assignment" }, - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" - }, "modelId": { "type": "string", "format": "uuid", @@ -7597,16 +29814,21 @@ "type": "string", "description": "The assigned role name", "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" } }, "required": [ "connectionId", - "membershipId", "modelId", - "roleName" + "roleName", + "userGroupId" ] }, - "UsersAssignModelRoleBody": { + "UserGroupsAssignModelRoleBody": { "type": "object", "properties": { "connectionId": { @@ -7631,367 +29853,432 @@ "required": [ "roleName" ] - }, - "UsersListEmailOnlyResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + } + }, + "parameters": {} + }, + "paths": { + "/api/v1/ai/generate-query": { + "post": { + "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", + "operationId": "aiGenerateQuery", + "summary": "Generate query from natural language", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "402": { + "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditShutoffError" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model or topic was not found in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/pick-topic": { + "post": { + "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", + "operationId": "aiPickTopic", + "summary": "Pick the best topic for a prompt", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicBody" + } + } + } + }, + "responses": { + "200": { + "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. The prompt or modelId may be missing or malformed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } }, - "records": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "description": "User email address", - "example": "user@example.com" - }, - "user_attributes": { - "type": "object", - "additionalProperties": {}, - "description": "User attributes as key-value pairs" - }, - "user_id": { - "type": "string", - "format": "uuid", - "description": "User ID" + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" } - }, - "required": [ - "email", - "user_attributes", - "user_id" - ] + } } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "UsersCreateEmailOnlyResponse": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" }, - "userId": { - "type": "string", - "format": "uuid", - "description": "ID of the created user" + "404": { + "description": "The specified model was not found, or no accessible topics exist in the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/search-omni-docs": { + "post": { + "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", + "operationId": "aiSearchOmniDocs", + "summary": "Search Omni documentation", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsBody" + } + } } }, - "required": [ - "email", - "userId" - ] - }, - "UsersCreateEmailOnlyBody": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" + "responses": { + "200": { + "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsResponse" + } + } + } }, - "userAttributes": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" + "400": { + "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" } - ] - }, - "description": "Optional user attributes as key-value pairs" - } - }, - "required": [ - "email" - ] - }, - "UsersCreateEmailOnlyBulkResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "ID of the created user" + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" } - }, - "required": [ - "email", - "userId" - ] - }, - "description": "Results for each created user" - } - }, - "required": [ - "results" - ] - }, - "UsersCreateEmailOnlyBulkBody": { - "type": "object", - "properties": { - "users": { - "type": "array", - "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" - }, - "userAttributes": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "Optional user attributes as key-value pairs" + } + } + }, + "403": { + "description": "Omni Agent is not enabled for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" } - }, - "required": [ - "email" - ] - }, - "minItems": 1, - "maxItems": 20, - "description": "Array of users to create (1-20 users)" + } + } + }, + "500": { + "description": "AI service error." } - }, - "required": [ - "users" - ] - }, - "UserGroupsGetModelRolesResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": { - "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" + } + } + }, + "/api/v1/ai/jobs": { + "post": { + "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", + "operationId": "aiJobSubmit", + "summary": "Submit an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" }, - "description": "List of role assignments" - }, - "userGroupId": { - "type": "string", - "description": "The user group short identifier", - "example": "abc123" + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitBody" + } + } } }, - "required": [ - "results", - "userGroupId" - ] - }, - "UserGroupRoleAssignmentResult": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "The base role definition name", - "example": "VIEWER" + "responses": { + "201": { + "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitResponse" + } + } + } }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection this role applies to" + "400": { + "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } }, - "from": { - "$ref": "#/components/schemas/UserGroupRoleOrigin" + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model this role applies to" + "403": { + "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } }, - "priority": { - "type": "number", - "description": "Priority for role resolution (higher = more permissive)" + "404": { + "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } }, - "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" + "409": { + "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } } - }, - "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "roleName" - ] - }, - "UserGroupRoleOrigin": { - "type": "object", - "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group (0 for direct assignment)" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { - "type": "string", - "description": "Name of the group", - "example": "Engineering Team" - }, - "type": { - "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role assigned to group" + } + } + }, + "/api/v1/ai/jobs/{jobId}": { + "get": { + "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", + "operationId": "aiJobStatus", + "summary": "Get AI job status", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" } - }, - "required": [ - "depth", - "miniUuid", - "name", - "type" ], - "description": "Origin of this role assignment" - }, - "UserGroupsAssignModelRoleResponse": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "The connection ID for this role assignment" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The model ID for this role assignment" - }, - "roleName": { - "type": "string", - "description": "The assigned role name", - "example": "VIEWER" + "responses": { + "200": { + "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobStatusResponse" + } + } + } }, - "userGroupId": { - "type": "string", - "description": "The user group short identifier", - "example": "abc123" - } - }, - "required": [ - "connectionId", - "modelId", - "roleName", - "userGroupId" - ] - }, - "UserGroupsAssignModelRoleBody": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model ID for model-level role assignment. Required if connectionId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } }, - "roleName": { - "type": "string", - "minLength": 1, - "description": "Name of the role to assign (base or custom role)", - "example": "VIEWER" + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } } - }, - "required": [ - "roleName" - ] + } } }, - "parameters": {} - }, - "paths": { - "/api/v1/ai/generate-query": { + "/api/v1/ai/jobs/{jobId}/cancel": { "post": { - "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", - "operationId": "aiGenerateQuery", - "summary": "Generate query from natural language", + "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", + "operationId": "aiJobCancel", + "summary": "Cancel an AI job", "tags": [ "AI" ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiGenerateQueryBody" - } - } + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" } - }, + ], "responses": { "200": { - "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed.", + "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiGenerateQueryResponse" + "$ref": "#/components/schemas/AiJobCancelResponse" } } } }, "400": { - "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", + "description": "Invalid job ID format. Must be a valid UUID.", "content": { "application/json": { "schema": { @@ -8011,7 +30298,7 @@ } }, "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", + "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", "content": { "application/json": { "schema": { @@ -8021,7 +30308,7 @@ } }, "404": { - "description": "The specified model or topic was not found in the organization.", + "description": "Job not found. The job may not exist or may belong to a different organization.", "content": { "application/json": { "schema": { @@ -8030,43 +30317,54 @@ } } }, - "500": { - "description": "AI service error." + "409": { + "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } } } } }, - "/api/v1/ai/pick-topic": { - "post": { - "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", - "operationId": "aiPickTopic", - "summary": "Pick the best topic for a prompt", + "/api/v1/ai/jobs/{jobId}/result": { + "get": { + "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", + "operationId": "aiJobResult", + "summary": "Get AI job result", "tags": [ "AI" ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiPickTopicBody" - } - } + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" } - }, + ], "responses": { "200": { - "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", + "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiPickTopicResponse" + "$ref": "#/components/schemas/AiJobResultResponse" } } } }, "400": { - "description": "Invalid request body. The prompt or modelId may be missing or malformed.", + "description": "Invalid job ID format. Must be a valid UUID.", "content": { "application/json": { "schema": { @@ -8085,18 +30383,75 @@ } } }, - "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", + "404": { + "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError403" + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/vis": { + "get": { + "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", + "operationId": "aiJobVisualization", + "summary": "Render AI job visualization", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "content": { + "image/png": { + "schema": { + "format": "binary", + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" } } } }, "404": { - "description": "The specified model was not found, or no accessible topics exist in the model.", + "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", "content": { "application/json": { "schema": { @@ -8105,47 +30460,114 @@ } } }, - "500": { - "description": "AI service error." + "422": { + "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError422" + } + } + } } } } }, - "/api/v1/ai/search-omni-docs": { - "post": { - "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", - "operationId": "aiSearchOmniDocs", - "summary": "Search Omni documentation", + "/api/v1/ai/branding": { + "get": { + "description": "Returns the organization's AI helper branding — display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", + "operationId": "aiBranding", + "summary": "Get AI helper branding", "tags": [ "AI" ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsBody" - } - } - } - }, "responses": { "200": { - "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", + "description": "AI branding retrieved successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsResponse" + "$ref": "#/components/schemas/AiBrandingResponse" } } } }, - "400": { - "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations": { + "get": { + "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next page.", + "operationId": "aiConversationsList", + "summary": "List AI conversations", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of conversations.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError400" + "$ref": "#/components/schemas/AiConversationsListResponse" } } } @@ -8161,7 +30583,7 @@ } }, "403": { - "description": "Omni Agent is not enabled for this organization.", + "description": "Insufficient permissions.", "content": { "application/json": { "schema": { @@ -8169,18 +30591,15 @@ } } } - }, - "500": { - "description": "AI service error." } } } }, - "/api/v1/ai/jobs": { - "post": { - "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", - "operationId": "aiJobSubmit", - "summary": "Submit an AI job", + "/api/v1/ai/conversations/{conversationId}": { + "get": { + "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", + "operationId": "aiConversationDetail", + "summary": "Get AI conversation with messages", "tags": [ "AI" ], @@ -8188,41 +30607,20 @@ { "schema": { "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" + "format": "uuid" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "name": "conversationId", + "in": "path" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitBody" - } - } - } - }, "responses": { - "201": { - "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitResponse" - } - } - } - }, - "400": { - "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", + "200": { + "description": "Conversation with messages in chronological order.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError400" + "$ref": "#/components/schemas/AiConversationDetailResponse" } } } @@ -8238,7 +30636,7 @@ } }, "403": { - "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", + "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", "content": { "application/json": { "schema": { @@ -8248,7 +30646,7 @@ } }, "404": { - "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", + "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user — existence of another user's conversations is not disclosed.", "content": { "application/json": { "schema": { @@ -8256,572 +30654,1529 @@ } } } + } + } + } + }, + "/api/v1/api-keys": { + "get": { + "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", + "operationId": "apiKeysList", + "summary": "List API tokens", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Cursor from the previous response (token UUID)" + }, + "required": false, + "description": "Cursor from the previous response (token UUID)", + "name": "cursor", + "in": "query" }, - "409": { - "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "createdAt", + "name" + ], + "default": "createdAt" + }, + "required": false, + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Filter by API token type. When omitted, all types are returned.", + "example": "personal" + }, + "required": false, + "description": "Filter by API token type. When omitted, all types are returned.", + "name": "type", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of API tokens", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError409" + "$ref": "#/components/schemas/ApiKeyListResponse" } } } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" } } } }, - "/api/v1/ai/jobs/{jobId}": { + "/api/v1/api-keys/{id}": { "get": { - "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", - "operationId": "aiJobStatus", - "summary": "Get AI job status", + "description": "Returns a single API token by id. Requires organization admin permissions.", + "operationId": "apiKeysGet", + "summary": "Get API token", "tags": [ - "AI" + "API Tokens" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" }, "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", + "description": "Token UUID", + "name": "id", "in": "path" } ], "responses": { "200": { - "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", + "description": "The requested API token", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiJobStatusResponse" + "$ref": "#/components/schemas/ApiKey" } } } }, "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "description": "Malformed `id` (must be a UUID)" }, "401": { - "description": "Missing or invalid API key.", + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + }, + "404": { + "description": "Token not found in this organization" + } + } + }, + "put": { + "description": "Enables or disables an API token. Requires organization admin permissions.", + "operationId": "apiKeysUpdate", + "summary": "Enable or disable an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "The updated API token", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError401" + "$ref": "#/components/schemas/ApiKey" } } } }, + "400": { + "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + }, + "delete": { + "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", + "operationId": "apiKeysDelete", + "summary": "Revoke an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The token was revoked", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError404" + "$ref": "#/components/schemas/ApiKeyDeleteResponse" } } } + }, + "400": { + "description": "Malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" } } } }, - "/api/v1/ai/jobs/{jobId}/cancel": { - "post": { - "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", - "operationId": "aiJobCancel", - "summary": "Cancel an AI job", + "/api/v1/connections": { + "get": { + "operationId": "connectionsList", + "summary": "List connections", "tags": [ - "AI" + "Connections" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Filter by database name (case-insensitive contains)", + "example": "analytics" }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" + "required": false, + "description": "Filter by database name (case-insensitive contains)", + "name": "database", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "example": "snowflake,bigquery" + }, + "required": false, + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "name": "dialect", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "description": "Include soft-deleted connections in results", + "example": false + }, + "required": false, + "description": "Include soft-deleted connections in results", + "name": "includeDeleted", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by connection name (case-insensitive contains)", + "example": "Production" + }, + "required": false, + "description": "Filter by connection name (case-insensitive contains)", + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "desc" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "database", + "dialect", + "name" + ], + "description": "Field to sort by", + "example": "name" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" } ], "responses": { "200": { - "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", + "description": "List of connections", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiJobCancelResponse" + "type": "object", + "properties": { + "connections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "description": "Whether branch environments override user attributes", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + }, + "description": "List of connections" + } + }, + "required": [ + "connections" + ], + "description": "List connections response", + "title": "ConnectionsListResponse" } } } - }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + }, + "post": { + "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", + "operationId": "connectionsCreate", + "summary": "Create connection", + "tags": [ + "Connections" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "acceptsLicense": { + "type": "boolean", + "description": "Acceptance of the license terms. Required for Oracle connections.", + "example": true + }, + "allowsUserSpecificTimezones": { + "type": "boolean", + "default": false, + "description": "Whether to allow users to specify their own timezones", + "example": false + }, + "alwaysScopeViewNames": { + "type": "boolean", + "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", + "example": true + }, + "authenticationType": { + "type": "string", + "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", + "example": "snowflake-password" + }, + "awsRoleArn": { + "type": "string", + "description": "AWS IAM role ARN. Applicable for Athena only.", + "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" + }, + "baseRole": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "RESTRICTED_QUERIER", + "QUERIER", + "MODELER", + "CONNECTION_ADMIN" + ], + "description": "The default role for users accessing the connection", + "example": "QUERIER" + }, + "database": { + "type": "string", + "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", + "example": "analytics_db" + }, + "defaultSchema": { + "type": "string", + "description": "The default schema to use. Required for MSSQL.", + "example": "public" + }, + "dialect": { + "type": "string", + "enum": [ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "exasol", + "mariadb", + "motherduck", + "mssql", + "mysql", + "oracle", + "postgres", + "redshift", + "sap_hana", + "snowflake", + "starrocks", + "trino" + ], + "description": "The database dialect", + "example": "snowflake" + }, + "enableDbSemanticLayerIntegration": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", + "example": false + }, + "enableDbSemanticLayerTopics": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", + "example": false + }, + "externalOauthAudience": { + "type": "string", + "description": "External OAuth audience claim. Applicable for Snowflake." + }, + "externalOauthAuthorizationUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/authorize" + }, + "externalOauthTokenUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/token" + }, + "host": { + "type": "string", + "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", + "example": "myaccount" + }, + "hostOverride": { + "type": "string", + "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", + "example": "myaccount.snowflakecomputing.com" + }, + "includeOtherCatalogs": { + "type": "string", + "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", + "example": "other_project1,other_project2" + }, + "includeSchemas": { + "type": "string", + "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", + "example": "public,analytics" + }, + "inferRelationshipsFromColumnNames": { + "type": "boolean", + "default": true, + "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", + "example": true + }, + "inferRelationshipsFromForeignKeys": { + "type": "boolean", + "default": false, + "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "example": false + }, + "maxBillingBytes": { + "type": "string", + "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", + "example": "1000000000" + }, + "name": { + "type": "string", + "description": "A descriptive name for the connection", + "example": "Production Warehouse" + }, + "oauthClientId": { + "type": "string", + "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "oauthClientSecretUnencrypted": { + "type": "string", + "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "offloadedSchemas": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", + "example": [ + "analytics_archive" + ] + }, + "passwordUnencrypted": { + "type": "string", + "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." + }, + "port": { + "type": "integer", + "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", + "example": 5432 + }, + "privateKey": { + "type": "string", + "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." + }, + "queryTimeoutSeconds": { + "type": "integer", + "maximum": 3600, + "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", + "example": 900 + }, + "queryTimezone": { + "type": "string", + "description": "The timezone to use for queries", + "example": "NONE" + }, + "region": { + "type": "string", + "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", + "example": "us-east-1" + }, + "scratchSchema": { + "type": "string", + "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", + "example": "omni_scratch" + }, + "systemTimezone": { + "type": "string", + "description": "The timezone to use for the system", + "example": "UTC" + }, + "trustServerCertificate": { + "type": "boolean", + "default": false, + "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", + "example": false + }, + "useMachineAuth": { + "type": "boolean", + "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "example": false + }, + "username": { + "type": "string", + "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", + "example": "analytics_user" + }, + "warehouse": { + "type": "string", + "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path).", + "example": "COMPUTE_WH" + } + }, + "required": [ + "dialect", + "name", + "passwordUnencrypted" + ], + "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", + "title": "ConnectionsCreateBody" } } - }, - "401": { - "description": "Missing or invalid API key.", + } + }, + "responses": { + "201": { + "description": "Connection created successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError401" + "type": "object", + "properties": { + "data": { + "type": "string", + "format": "uuid", + "description": "Created connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "data", + "success" + ], + "description": "Create connection response", + "title": "ConnectionsCreateResponse" } } } }, - "403": { - "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "400": { + "description": "Invalid request body or dialect" }, - "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "401": { + "description": "Authentication required" }, - "409": { - "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } + "403": { + "description": "Permission denied - admin role required" } } } }, - "/api/v1/ai/jobs/{jobId}/result": { + "/api/v1/connections/{id}": { "get": { - "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", - "operationId": "aiJobResult", - "summary": "Get AI job result", + "description": "Fetch a single connection by ID.", + "operationId": "connectionsGet", + "summary": "Get connection", "tags": [ - "AI" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", + "description": "Connection ID", + "name": "id", "in": "path" } ], "responses": { "200": { - "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", + "description": "Connection object", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiJobResultResponse" - } - } - } - }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" + "type": "object", + "properties": { + "connection": { + "type": "object", + "properties": { + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "description": "Whether branch environments override user attributes", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + } + }, + "required": [ + "connection" + ], + "description": "Get connection response", + "title": "ConnectionsGetResponse" } } } }, "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "description": "Authentication required" + }, + "403": { + "description": "Permission denied — caller lacks READ on the connection" }, "404": { - "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "description": "Connection does not exist" } } - } - }, - "/api/v1/ai/jobs/{jobId}/vis": { - "get": { - "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", - "operationId": "aiJobVisualization", - "summary": "Render AI job visualization", + }, + "patch": { + "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", + "operationId": "connectionsUpdate", + "summary": "Update connection", "tags": [ - "AI" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", + "description": "Connection ID", + "name": "id", "in": "path" } - ], + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "Default role to assign to this connection", + "example": "QUERIER" + }, + "environmentUserAttribute": { + "type": [ + "object", + "null" + ], + "properties": { + "attributeName": { + "type": "string", + "description": "Name of the user attribute for environment selection", + "example": "region" + }, + "defaultValues": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default values for the user attribute", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "attributeName", + "defaultValues" + ], + "description": "User attribute settings for connection environments" + }, + "passwordUnencrypted": { + "type": "string", + "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." + }, + "privateKey": { + "type": "string", + "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." + } + }, + "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", + "title": "ConnectionsUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "description": "Connection updated successfully", "content": { - "image/png": { + "application/json": { "schema": { - "format": "binary", - "type": "string" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing what was updated", + "example": "Updated connection default role." + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Update connection response", + "title": "ConnectionsUpdateResponse" } } } }, "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "description": "Invalid request body - at least one field must be provided" }, "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "description": "Authentication required" }, - "404": { - "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "403": { + "description": "Permission denied - connection admin role required" }, - "422": { - "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError422" - } - } - } + "404": { + "description": "Connection not found" } } - } - }, - "/api/v1/api-keys": { - "get": { - "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", - "operationId": "apiKeysList", - "summary": "List API tokens", + }, + "delete": { + "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", + "operationId": "connectionsDelete", + "summary": "Delete connection", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Cursor from the previous response (token UUID)" - }, - "required": false, - "description": "Cursor from the previous response (token UUID)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "number", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "createdAt", - "name" - ], - "default": "createdAt" - }, - "required": false, - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "personal", - "mcp" - ], - "description": "Filter by API token type. When omitted, all types are returned.", - "example": "personal" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Filter by API token type. When omitted, all types are returned.", - "name": "type", - "in": "query" + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" } ], "responses": { "200": { - "description": "Paginated list of API tokens", + "description": "Connection moved to trash", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyListResponse" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing the result", + "example": "Connection moved to trash." + }, + "success": { + "type": "boolean", + "description": "True when the connection was archived", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Archive connection response", + "title": "ConnectionsDeleteResponse" } } } }, - "400": { - "description": "Invalid query parameters" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions" + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + }, + "410": { + "description": "Connection has already been archived" } } } }, - "/api/v1/api-keys/{id}": { + "/api/v1/connections/{connectionId}/dbt": { "get": { - "description": "Returns a single API token by id. Requires organization admin permissions.", - "operationId": "apiKeysGet", - "summary": "Get API token", + "operationId": "connectionsDbtGet", + "summary": "Get dbt configuration", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", - "name": "id", + "description": "Connection ID", + "name": "connectionId", "in": "path" } ], "responses": { "200": { - "description": "The requested API token", + "description": "dbt configuration for the connection", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKey" + "anyOf": [ + { + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Whether relationships are auto-generated from dbt", + "example": true + }, + "branch": { + "type": "string", + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": "string", + "description": "dbt version being used", + "example": "Auto" + }, + "enableSemanticLayer": { + "type": "boolean", + "description": "Whether the dbt semantic layer integration is enabled", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Whether virtual schemas are enabled", + "example": false + }, + "projectRootPath": { + "type": [ + "string", + "null" + ], + "description": "Path to dbt project root", + "example": "dbt_project" + }, + "sshUrl": { + "type": "string", + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + }, + "supportsDbt": { + "type": "boolean", + "enum": [ + true + ], + "description": "Indicates dbt is supported and configured", + "example": true + } + }, + "required": [ + "autogenRelationships", + "branch", + "dbtVersion", + "enableSemanticLayer", + "enableVirtualSchemas", + "projectRootPath", + "sshUrl", + "supportsDbt" + ], + "description": "dbt repository configuration response", + "title": "DbtConfiguredResponse" + }, + { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message explaining dbt status", + "example": "dbt not configured for this connection" + }, + "supportsDbt": { + "type": "boolean", + "description": "Whether the connection dialect supports dbt", + "example": true + } + }, + "required": [ + "message", + "supportsDbt" + ], + "description": "Response when dbt is not configured", + "title": "DbtNotConfiguredResponse" + } + ], + "description": "dbt configuration response", + "title": "ConnectionsDbtGetResponse" } } } }, - "400": { - "description": "Malformed `id` (must be a UUID)" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Token not found in this organization" + "description": "Connection not found" } } }, "put": { - "description": "Enables or disables an organization-level API token. Personal access tokens and MCP OAuth grants do not support this operation. Requires organization admin permissions.", - "operationId": "apiKeysUpdate", - "summary": "Enable or disable an organization API token", + "operationId": "connectionsDbtUpdate", + "summary": "Update dbt configuration", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", - "name": "id", + "description": "Connection ID", + "name": "connectionId", "in": "path" } ], "requestBody": { - "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyUpdateBody" + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Automatically generate relationships from dbt", + "example": true + }, + "branch": { + "type": "string", + "minLength": 1, + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": [ + "string", + "null" + ], + "description": "dbt version to use. Supported: Auto, 1.10, 1.11", + "example": "1.11" + }, + "enableSemanticLayer": { + "type": "boolean", + "default": false, + "description": "Enable dbt semantic layer integration", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Enable virtual schemas from dbt", + "example": false + }, + "projectRootPath": { + "anyOf": [ + { + "type": "string", + "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" + }, + { + "type": "string", + "enum": [ + "" + ] + }, + { + "type": [ + "object", + "null" + ], + "enum": [ + null + ] + }, + { + "type": "null" + } + ], + "default": null, + "description": "Path to dbt project root within repository", + "example": "dbt_project" + }, + "rotateKeys": { + "type": "boolean", + "default": false, + "description": "Rotate SSH deploy keys", + "example": false + }, + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + } + }, + "required": [ + "autogenRelationships", + "branch", + "enableVirtualSchemas", + "sshUrl" + ], + "description": "dbt repository configuration", + "title": "ConnectionsDbtUpdateBody" } } } }, "responses": { "200": { - "description": "The updated API token", + "description": "dbt configuration updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKey" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt configuration updated successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt update response", + "title": "ConnectionsDbtUpdateResponse" } } } }, "400": { - "description": "Invalid body, malformed `id`, target is not an organization token, or missing/malformed `Authorization` header" + "description": "Invalid request body or validation error" + }, + "401": { + "description": "Authentication required" }, "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" + "description": "Connection not found" } } }, "delete": { - "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", - "operationId": "apiKeysDelete", - "summary": "Revoke an API token", + "operationId": "connectionsDbtDelete", + "summary": "Delete dbt configuration", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", - "name": "id", + "description": "Connection ID", + "name": "connectionId", "in": "path" } ], "responses": { "200": { - "description": "The token was revoked", + "description": "dbt configuration deleted successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyDeleteResponse" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt repository unlinked successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt delete response", + "title": "ConnectionsDbtDeleteResponse" } } } }, - "400": { - "description": "Malformed `id`, or missing/malformed `Authorization` header" + "401": { + "description": "Authentication required" }, "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" + "description": "Connection not found or dbt not configured" } } } }, - "/api/v1/connections": { + "/api/v1/connections/{connectionId}/dbt/environments": { "get": { - "operationId": "connectionsList", - "summary": "List connections", + "description": "List all dbt environments for a connection.", + "operationId": "connectionsDbtEnvironmentsList", + "summary": "List dbt environments", "tags": [ "Connections" ], @@ -8829,45 +32184,38 @@ { "schema": { "type": "string", - "description": "Filter by database name (case-insensitive contains)", - "example": "analytics" + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Filter by database name (case-insensitive contains)", - "name": "database", - "in": "query" + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" }, { "schema": { "type": "string", - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "example": "snowflake,bigquery" - }, - "required": false, - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "name": "dialect", - "in": "query" - }, - { - "schema": { - "type": "boolean", - "description": "Include soft-deleted connections in results", - "example": false + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" }, "required": false, - "description": "Include soft-deleted connections in results", - "name": "includeDeleted", + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", "in": "query" }, { - "schema": { - "type": "string", - "description": "Filter by connection name (case-insensitive contains)", - "example": "Production" + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 }, "required": false, - "description": "Filter by connection name (case-insensitive contains)", - "name": "name", + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", "in": "query" }, { @@ -8877,11 +32225,12 @@ "asc", "desc" ], - "description": "Sort direction", + "default": "desc", + "description": "Sort direction for results", "example": "desc" }, "required": false, - "description": "Sort direction", + "description": "Sort direction for results", "name": "sortDirection", "in": "query" }, @@ -8889,472 +32238,782 @@ "schema": { "type": "string", "enum": [ - "database", - "dialect", "name" ], - "description": "Field to sort by", + "default": "name", + "description": "Field to sort results by", "example": "name" }, "required": false, - "description": "Field to sort by", + "description": "Field to sort results by", "name": "sortField", "in": "query" } ], "responses": { "200": { - "description": "List of connections", + "description": "List of dbt environments", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseRole": { - "type": [ - "string", - "null" - ], - "description": "Default role for users on this connection", - "example": "QUERIER" - }, - "branchConnectionEnvironmentOverridesUserAttr": { - "type": [ - "boolean", - "null" - ], - "description": "Whether branch environments override user attributes", - "example": false - }, - "database": { - "type": [ - "string", - "null" - ], - "description": "Database name", - "example": "analytics_db" - }, - "defaultSchema": { - "type": [ - "string", - "null" - ], - "description": "Default schema for the connection", - "example": "public" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when connection was deleted (ISO 8601)", - "example": null - }, - "dialect": { - "type": "string", - "enum": [ - "snowflake", - "bigquery", - "redshift", - "postgres", - "mysql", - "mariadb", - "databricks", - "databricks_lakebase", - "trino", - "athena", - "duckdb", - "motherduck", - "sqlserver", - "clickhouse", - "singlestore" - ], - "description": "Database dialect type", - "example": "snowflake" - }, - "environmentConnectionSwitchesSchemaModel": { - "type": [ - "boolean", - "null" - ], - "description": "Whether environment connections switch schema model", - "example": false - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection identifier", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "name": { - "type": "string", - "description": "Connection display name", - "example": "Production Snowflake" - }, - "userAttributeNameForConnectionsEnvironments": { - "type": [ - "string", - "null" - ], - "description": "User attribute name used for connection environments", - "example": "region" - }, - "userAttributeValuesForDefaultEnvironment": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default user attribute values for the base environment", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "baseRole", - "branchConnectionEnvironmentOverridesUserAttr", - "database", - "defaultSchema", - "deletedAt", - "dialect", - "environmentConnectionSwitchesSchemaModel", - "id", - "name", - "userAttributeNameForConnectionsEnvironments", - "userAttributeValuesForDefaultEnvironment" - ], - "description": "Connection object", - "title": "Connection" - }, - "description": "List of connections" + "$ref": "#/components/schemas/DbtEnvironmentListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection not found" + } + } + }, + "post": { + "description": "Create a new dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsCreate", + "summary": "Create dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "dbt environment created successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" + }, + { + "description": "Created dbt environment", + "title": "DbtEnvironmentCreateResponse" + } + ] + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { + "put": { + "description": "Update an existing dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsUpdate", + "summary": "Update dbt environment", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt environment updated successfully", + "content": { + "application/json": { + "schema": { + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" + }, + { + "description": "Updated dbt environment", + "title": "DbtEnvironmentUpdateResponse" } - }, - "required": [ - "connections" - ], - "description": "List connections response", - "title": "ConnectionsListResponse" + ] } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" } } }, - "post": { - "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", - "operationId": "connectionsCreate", - "summary": "Create connection", + "delete": { + "description": "Delete a dbt environment from a connection.", + "operationId": "connectionsDbtEnvironmentsDelete", + "summary": "Delete dbt environment", "tags": [ "Connections" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "acceptsLicense": { - "type": "boolean", - "description": "Acceptance of the license terms. Required for Oracle connections.", - "example": true - }, - "allowsUserSpecificTimezones": { - "type": "boolean", - "default": false, - "description": "Whether to allow users to specify their own timezones", - "example": false - }, - "alwaysScopeViewNames": { - "type": "boolean", - "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", - "example": true - }, - "authenticationType": { - "type": "string", - "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", - "example": "snowflake-password" - }, - "awsRoleArn": { - "type": "string", - "description": "AWS IAM role ARN. Applicable for Athena only.", - "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" - }, - "baseRole": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "RESTRICTED_QUERIER", - "QUERIER", - "MODELER", - "CONNECTION_ADMIN" - ], - "description": "The default role for users accessing the connection", - "example": "QUERIER" - }, - "database": { - "type": "string", - "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", - "example": "analytics_db" - }, - "defaultSchema": { - "type": "string", - "description": "The default schema to use. Required for MSSQL.", - "example": "public" - }, - "dialect": { - "type": "string", - "enum": [ - "athena", - "bigquery", - "clickhouse", - "databricks", - "databricks_lakebase", - "exasol", - "mariadb", - "motherduck", - "mssql", - "mysql", - "oracle", - "postgres", - "redshift", - "sap_hana", - "snowflake", - "starrocks", - "trino" - ], - "description": "The database dialect", - "example": "snowflake" - }, - "enableDbSemanticLayerIntegration": { - "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", - "example": false - }, - "enableDbSemanticLayerTopics": { - "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", - "example": false - }, - "externalOauthAudience": { - "type": "string", - "description": "External OAuth audience claim. Applicable for Snowflake." - }, - "externalOauthAuthorizationUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/authorize" - }, - "externalOauthTokenUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/token" - }, - "host": { - "type": "string", - "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", - "example": "myaccount" - }, - "hostOverride": { - "type": "string", - "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", - "example": "myaccount.snowflakecomputing.com" - }, - "includeOtherCatalogs": { - "type": "string", - "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", - "example": "other_project1,other_project2" - }, - "includeSchemas": { - "type": "string", - "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", - "example": "public,analytics" - }, - "inferRelationshipsFromColumnNames": { - "type": "boolean", - "default": true, - "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", - "example": true + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt environment deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/schedules": { + "get": { + "operationId": "connectionsSchedulesList", + "summary": "List schema refresh schedules", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "List of schema refresh schedules", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "schedules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Schema refresh schedule object", + "title": "ConnectionSchedule" + }, + "description": "List of schema refresh schedules" + } }, - "inferRelationshipsFromForeignKeys": { + "required": [ + "schedules" + ], + "description": "List schedules response", + "title": "ConnectionsSchedulesListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "post": { + "operationId": "connectionsSchedulesCreate", + "summary": "Create schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { "type": "boolean", "default": false, - "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", "example": false }, - "maxBillingBytes": { - "type": "string", - "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", - "example": "1000000000" - }, - "name": { - "type": "string", - "description": "A descriptive name for the connection", - "example": "Production Warehouse" - }, - "oauthClientId": { - "type": "string", - "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." - }, - "oauthClientSecretUnencrypted": { - "type": "string", - "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." - }, - "offloadedSchemas": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "array", - "items": { - "type": "string" - } - } - ], - "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", - "example": [ - "analytics_archive" - ] - }, - "passwordUnencrypted": { - "type": "string", - "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." - }, - "port": { - "type": "integer", - "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", - "example": 5432 - }, - "privateKey": { - "type": "string", - "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." - }, - "queryTimeoutSeconds": { - "type": "integer", - "maximum": 3600, - "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", - "example": 900 - }, - "queryTimezone": { - "type": "string", - "description": "The timezone to use for queries", - "example": "NONE" - }, - "region": { + "schedule": { "type": "string", - "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", - "example": "us-east-1" + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" }, - "scratchSchema": { + "timezone": { "type": "string", - "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", - "example": "omni_scratch" + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for creating a schema refresh schedule", + "title": "ConnectionsSchedulesCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Schema refresh schedule created successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } }, - "systemTimezone": { - "type": "string", - "description": "The timezone to use for the system", - "example": "UTC" + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Created schedule response", + "title": "ConnectionsSchedulesCreateResponse" + } + } + } + }, + "400": { + "description": "Invalid cron expression or timezone" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + } + }, + "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { + "get": { + "operationId": "connectionsSchedulesGet", + "summary": "Get schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Schema refresh schedule details", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } }, - "trustServerCertificate": { + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Get schedule response", + "title": "ConnectionsSchedulesGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" + } + } + }, + "put": { + "operationId": "connectionsSchedulesUpdate", + "summary": "Update schema refresh schedule", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { "type": "boolean", "default": false, - "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", - "example": false - }, - "useMachineAuth": { - "type": "boolean", - "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", "example": false }, - "username": { + "schedule": { "type": "string", - "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", - "example": "analytics_user" + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" }, - "warehouse": { + "timezone": { "type": "string", - "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path).", - "example": "COMPUTE_WH" + "description": "IANA timezone for schedule execution", + "example": "America/New_York" } }, "required": [ - "dialect", - "name", - "passwordUnencrypted" + "schedule", + "timezone" ], - "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", - "title": "ConnectionsCreateBody" + "description": "Request body for updating a schema refresh schedule", + "title": "ConnectionsSchedulesUpdateBody" } } } }, "responses": { - "201": { - "description": "Connection created successfully", + "200": { + "description": "Schema refresh schedule updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "data": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { "type": "string", "format": "uuid", - "description": "Created connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" } }, "required": [ - "data", - "success" + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" ], - "description": "Create connection response", - "title": "ConnectionsCreateResponse" + "description": "Updated schedule response", + "title": "ConnectionsSchedulesUpdateResponse" } } } }, "400": { - "description": "Invalid request body or dialect" + "description": "Invalid cron expression or timezone" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" } } - } - }, - "/api/v1/connections/{id}": { - "patch": { - "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", - "operationId": "connectionsUpdate", - "summary": "Update connection", + }, + "delete": { + "operationId": "connectionsSchedulesDelete", + "summary": "Delete schema refresh schedule", "tags": [ "Connections" ], @@ -9368,81 +33027,30 @@ }, "required": true, "description": "Connection ID", - "name": "id", + "name": "connectionId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "Default role to assign to this connection", - "example": "QUERIER" - }, - "environmentUserAttribute": { - "type": [ - "object", - "null" - ], - "properties": { - "attributeName": { - "type": "string", - "description": "Name of the user attribute for environment selection", - "example": "region" - }, - "defaultValues": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default values for the user attribute", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "attributeName", - "defaultValues" - ], - "description": "User attribute settings for connection environments" - }, - "passwordUnencrypted": { - "type": "string", - "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." - }, - "privateKey": { - "type": "string", - "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." - } - }, - "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", - "title": "ConnectionsUpdateBody" - } - } - } - }, "responses": { "200": { - "description": "Connection updated successfully", + "description": "Schema refresh schedule deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "Status message describing what was updated", - "example": "Updated connection default role." - }, "success": { "type": "boolean", "description": "Whether the operation succeeded", @@ -9450,18 +33058,14 @@ } }, "required": [ - "message", "success" ], - "description": "Update connection response", - "title": "ConnectionsUpdateResponse" + "description": "Delete schedule response", + "title": "ConnectionsSchedulesDeleteResponse" } } } }, - "400": { - "description": "Invalid request body - at least one field must be provided" - }, "401": { "description": "Authentication required" }, @@ -9469,144 +33073,214 @@ "description": "Permission denied - connection admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection or schedule not found" } } } }, - "/api/v1/connections/{connectionId}/dbt": { + "/api/v1/connection-environments": { "get": { - "operationId": "connectionsDbtGet", - "summary": "Get dbt configuration", + "operationId": "connectionEnvironmentsList", + "summary": "List connection environments", "tags": [ "Connections" ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "responses": { + "200": { + "description": "List of connection environments", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" + }, + "description": "List of connection environments" + } + }, + "required": [ + "connectionEnvironments" + ], + "description": "List connection environments response", + "title": "ConnectionsEnvironmentsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - admin role required" + } + } + }, + "post": { + "operationId": "connectionEnvironmentsCreate", + "summary": "Create connection environments", + "tags": [ + "Connections" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "environmentConnectionIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "IDs of connections to use as environments", + "example": [ + "550e8400-e29b-41d4-a716-446655440002", + "550e8400-e29b-41d4-a716-446655440003" + ] + } + }, + "required": [ + "baseConnectionId", + "environmentConnectionIds" + ], + "description": "Request body for creating connection environments", + "title": "ConnectionsEnvironmentsCreateBody" + } + } } - ], + }, "responses": { - "200": { - "description": "dbt configuration for the connection", + "201": { + "description": "Connection environments created successfully", "content": { "application/json": { "schema": { - "anyOf": [ - { - "type": "object", - "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Whether relationships are auto-generated from dbt", - "example": true - }, - "branch": { - "type": "string", - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": "string", - "description": "dbt version being used", - "example": "Auto" - }, - "enableSemanticLayer": { - "type": "boolean", - "description": "Whether the dbt semantic layer integration is enabled", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Whether virtual schemas are enabled", - "example": false - }, - "projectRootPath": { - "type": [ - "string", - "null" - ], - "description": "Path to dbt project root", - "example": "dbt_project" - }, - "sshUrl": { - "type": "string", - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" - }, - "supportsDbt": { - "type": "boolean", - "enum": [ - true - ], - "description": "Indicates dbt is supported and configured", - "example": true - } - }, - "required": [ - "autogenRelationships", - "branch", - "dbtVersion", - "enableSemanticLayer", - "enableVirtualSchemas", - "projectRootPath", - "sshUrl", - "supportsDbt" - ], - "description": "dbt repository configuration response", - "title": "DbtConfiguredResponse" - }, - { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Message explaining dbt status", - "example": "dbt not configured for this connection" + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } }, - "supportsDbt": { - "type": "boolean", - "description": "Whether the connection dialect supports dbt", - "example": true - } + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" }, - "required": [ - "message", - "supportsDbt" - ], - "description": "Response when dbt is not configured", - "title": "DbtNotConfiguredResponse" + "description": "Created connection environments" } + }, + "required": [ + "connectionEnvironments" ], - "description": "dbt configuration response", - "title": "ConnectionsDbtGetResponse" + "description": "Create connection environments response", + "title": "ConnectionsEnvironmentsCreateResponse" } } } }, + "400": { + "description": "Invalid request body or connection IDs" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found" + "description": "Base connection or environment connection not found" } } - }, + } + }, + "/api/v1/connection-environments/{id}": { "put": { - "operationId": "connectionsDbtUpdate", - "summary": "Update dbt configuration", + "operationId": "connectionEnvironmentsUpdate", + "summary": "Update connection environment", "tags": [ "Connections" ], @@ -9615,12 +33289,12 @@ "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Connection environment ID", + "name": "id", "in": "path" } ], @@ -9630,103 +33304,35 @@ "schema": { "type": "object", "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Automatically generate relationships from dbt", - "example": true - }, - "branch": { - "type": "string", - "minLength": 1, - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": [ - "string", - "null" - ], - "description": "dbt version to use. Supported: Auto, 1.10, 1.11", - "example": "1.11" - }, - "enableSemanticLayer": { - "type": "boolean", - "default": false, - "description": "Enable dbt semantic layer integration", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Enable virtual schemas from dbt", - "example": false - }, - "projectRootPath": { - "anyOf": [ - { - "type": "string", - "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" - }, - { - "type": "string", - "enum": [ - "" - ] - }, - { - "type": [ - "object", - "null" - ], - "enum": [ - null - ] - }, - { - "type": "null" - } - ], - "default": null, - "description": "Path to dbt project root within repository", - "example": "dbt_project" - }, - "rotateKeys": { - "type": "boolean", - "default": false, - "description": "Rotate SSH deploy keys", - "example": false - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] } }, "required": [ - "autogenRelationships", - "branch", - "enableVirtualSchemas", - "sshUrl" + "userAttributeValues" ], - "description": "dbt repository configuration", - "title": "ConnectionsDbtUpdateBody" + "description": "Request body for updating a connection environment", + "title": "ConnectionsEnvironmentsUpdateBody" } } } }, "responses": { "200": { - "description": "dbt configuration updated successfully", + "description": "Connection environment updated successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "dbt configuration updated successfully" - }, "success": { "type": "boolean", "description": "Whether the operation succeeded", @@ -9734,32 +33340,31 @@ } }, "required": [ - "message", "success" ], - "description": "dbt update response", - "title": "ConnectionsDbtUpdateResponse" + "description": "Update connection environment response", + "title": "ConnectionsEnvironmentsUpdateResponse" } } } }, "400": { - "description": "Invalid request body or validation error" + "description": "Invalid request body" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection environment not found" } } }, "delete": { - "operationId": "connectionsDbtDelete", - "summary": "Delete dbt configuration", + "operationId": "connectionEnvironmentsDelete", + "summary": "Delete connection environment", "tags": [ "Connections" ], @@ -9768,28 +33373,23 @@ "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Connection environment ID", + "name": "id", "in": "path" } ], "responses": { "200": { - "description": "dbt configuration deleted successfully", + "description": "Connection environment deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "dbt repository unlinked successfully" - }, "success": { "type": "boolean", "description": "Whether the operation succeeded", @@ -9797,11 +33397,10 @@ } }, "required": [ - "message", "success" ], - "description": "dbt delete response", - "title": "ConnectionsDbtDeleteResponse" + "description": "Delete connection environment response", + "title": "ConnectionsEnvironmentsDeleteResponse" } } } @@ -9810,35 +33409,22 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found or dbt not configured" + "description": "Connection environment not found" } } } }, - "/api/v1/connections/{connectionId}/dbt/environments": { + "/api/v1/content": { "get": { - "description": "List all dbt environments for a connection.", - "operationId": "connectionsDbtEnvironmentsList", - "summary": "List dbt environments", + "operationId": "contentList", + "summary": "List content", "tags": [ - "Connections" + "Content" ], "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, { "schema": { "type": "string", @@ -9852,617 +33438,359 @@ }, { "schema": { - "type": "number", + "type": "integer", "minimum": 1, "maximum": 100, "default": 20, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "example": 20 }, "required": false, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "name": "pageSize", "in": "query" }, { "schema": { "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name" - ], - "default": "name", - "description": "Field to sort results by", - "example": "name" + "format": "uuid", + "description": "Filter by creator user ID" }, "required": false, - "description": "Field to sort results by", - "name": "sortField", + "description": "Filter by creator user ID", + "name": "creatorId", "in": "query" - } - ], - "responses": { - "200": { - "description": "List of dbt environments", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection not found" - } - } - }, - "post": { - "description": "Create a new dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsCreate", - "summary": "Create dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "dbt environment created successfully", - "content": { - "application/json": { - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentItem" - }, - { - "description": "Created dbt environment", - "title": "DbtEnvironmentCreateResponse" - } - ] - } - } - } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection not found" - } - } - } - }, - "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { - "put": { - "description": "Update an existing dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsUpdate", - "summary": "Update dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + "description": "Filter by folder ID (cannot be used with path)" }, - "required": true, - "description": "Environment ID", - "name": "environmentId", - "in": "path" - } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" - } - } - } - }, - "responses": { - "200": { - "description": "dbt environment updated successfully", - "content": { - "application/json": { - "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentItem" - }, - { - "description": "Updated dbt environment", - "title": "DbtEnvironmentUpdateResponse" - } - ] - } - } - } + "required": false, + "description": "Filter by folder ID (cannot be used with path)", + "name": "folderId", + "in": "query" }, - "400": { - "description": "Invalid request body" + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (e.g., _count,labels)" + }, + "required": false, + "description": "Comma-separated list of fields to include (e.g., _count,labels)", + "name": "include", + "in": "query" }, - "401": { - "description": "Authentication required" + { + "schema": { + "type": "string", + "description": "Filter by folder path (cannot be used with folderId)", + "example": "/reports/sales" + }, + "required": false, + "description": "Filter by folder path (cannot be used with folderId)", + "name": "path", + "in": "query" }, - "403": { - "description": "Permission denied or connection does not support dbt" + { + "schema": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Filter by share scope", + "example": "organization" + }, + "required": false, + "description": "Filter by share scope", + "name": "scope", + "in": "query" }, - "404": { - "description": "Connection or environment not found" - } - } - }, - "delete": { - "description": "Delete a dbt environment from a connection.", - "operationId": "connectionsDbtEnvironmentsDelete", - "summary": "Delete dbt environment", - "tags": [ - "Connections" - ], - "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "asc" }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + "enum": [ + "name", + "favorites" + ], + "description": "Field to sort by", + "example": "name" }, - "required": true, - "description": "Environment ID", - "name": "environmentId", - "in": "path" + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" } ], "responses": { "200": { - "description": "dbt environment deleted successfully", + "description": "List of content (documents and folders)", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + "$ref": "#/components/schemas/ContentListResponse" } } } }, + "400": { + "description": "Invalid query parameters (cannot use both folderId and path)" + }, "401": { "description": "Authentication required" }, - "403": { - "description": "Permission denied or connection does not support dbt" - }, "404": { - "description": "Connection or environment not found" + "description": "Folder not found (when filtering by path)" } } } }, - "/api/v1/connections/{connectionId}/schedules": { - "get": { - "operationId": "connectionsSchedulesList", - "summary": "List schema refresh schedules", + "/api/v1/dashboards/{identifier}/download": { + "post": { + "operationId": "dashboardsDownload", + "summary": "Initiate dashboard download", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" - } - ], - "responses": { - "200": { - "description": "List of schema refresh schedules", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Schema refresh schedule object", - "title": "ConnectionSchedule" - }, - "description": "List of schema refresh schedules" - } - }, - "required": [ - "schedules" - ], - "description": "List schedules response", - "title": "ConnectionsSchedulesListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" }, - "404": { - "description": "Connection not found" - } - } - }, - "post": { - "operationId": "connectionsSchedulesCreate", - "summary": "Create schema refresh schedule", - "tags": [ - "Connections" - ], - "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Target user membership ID (for org-scoped API keys)" }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for creating a schema refresh schedule", - "title": "ConnectionsSchedulesCreateBody" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsDownloadBody" } } } }, "responses": { - "201": { - "description": "Schema refresh schedule created successfully", + "200": { + "description": "Download job initiated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Created schedule response", - "title": "ConnectionsSchedulesCreateResponse" + "$ref": "#/components/schemas/DashboardsDownloadResponse" } } } }, "400": { - "description": "Invalid cron expression or timezone" + "description": "Invalid request body or filter configuration" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - cannot download this dashboard" }, "404": { - "description": "Connection not found" + "description": "Dashboard not found" + }, + "409": { + "description": "Download already in progress for this dashboard" + }, + "500": { + "description": "Failed to initiate download" } } } }, - "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { + "/api/v1/dashboards/{identifier}/download/{jobId}": { "get": { - "operationId": "connectionsSchedulesGet", - "summary": "Get schema refresh schedule", + "operationId": "dashboardsDownloadFile", + "summary": "Get download file", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "File ready - binary content streamed" + }, + "202": { + "description": "Download job still in progress" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Dashboard or download job not found" + }, + "410": { + "description": "Download job failed" + }, + "500": { + "description": "Failed to retrieve download artifact" + } + } + } + }, + "/api/v1/dashboards/{identifier}/download/{jobId}/status": { + "get": { + "operationId": "dashboardsDownloadStatus", + "summary": "Get download job status", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Schedule ID", - "name": "scheduleId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "responses": { "200": { - "description": "Schema refresh schedule details", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Get schedule response", - "title": "ConnectionsSchedulesGetResponse" + "description": "Download job status" + }, + "401": { + "description": "Authentication required" + }, + "404": { + "description": "Dashboard or download job not found" + } + } + } + }, + "/api/v1/dashboards/{identifier}/filters": { + "get": { + "operationId": "dashboardsGetFilters", + "summary": "Get dashboard filters", + "tags": [ + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Dashboard filter and control configuration", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardFiltersResponse" } } } @@ -10471,440 +33799,319 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - VIEWER role required" }, "404": { - "description": "Connection or schedule not found" + "description": "Dashboard not found" } } }, - "put": { - "operationId": "connectionsSchedulesUpdate", - "summary": "Update schema refresh schedule", + "patch": { + "operationId": "dashboardsUpdateFilters", + "summary": "Update dashboard filters", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Target user membership ID (for org-scoped API keys)" }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for updating a schema refresh schedule", - "title": "ConnectionsSchedulesUpdateBody" + "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" } } } }, "responses": { "200": { - "description": "Schema refresh schedule updated successfully", + "description": "Filters updated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Updated schedule response", - "title": "ConnectionsSchedulesUpdateResponse" + "$ref": "#/components/schemas/DashboardFiltersResponse" } } } }, "400": { - "description": "Invalid cron expression or timezone" + "description": "Invalid request body - must include at least one filter, control, or filterOrder" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - EDITOR role required" }, "404": { - "description": "Connection or schedule not found" + "description": "Dashboard not found or document does not have a dashboard" + }, + "409": { + "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." } } - }, - "delete": { - "operationId": "connectionsSchedulesDelete", - "summary": "Delete schema refresh schedule", + } + }, + "/api/v1/documents": { + "get": { + "operationId": "documentsList", + "summary": "List documents", "tags": [ - "Connections" + "Documents" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Filter by creator membership ID" + }, + "required": false, + "description": "Filter by creator membership ID", + "name": "creatorId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination" + }, + "required": false, + "description": "Cursor for pagination", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by folder ID" + }, + "required": false, + "description": "Filter by folder ID", + "name": "folderId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "example": "_count,labels" + }, + "required": false, + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of label names to filter by", + "example": "verified,important" + }, + "required": false, + "description": "Comma-separated list of label names to filter by", + "name": "labels", + "in": "query" + }, + { + "schema": { + "type": "integer", + "exclusiveMinimum": 0, + "default": 50, + "description": "Number of records per page" + }, + "required": false, + "description": "Number of records per page", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name", + "favorites", + "updatedAt", + "visits" + ], + "default": "name", + "description": "Field to sort by" }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" }, { "schema": { "type": "string", "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Filter documents visible to this membership ID" }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" + "required": false, + "description": "Filter documents visible to this membership ID", + "name": "userId", + "in": "query" } ], "responses": { "200": { - "description": "Schema refresh schedule deleted successfully", + "description": "Paginated list of documents", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete schedule response", - "title": "ConnectionsSchedulesDeleteResponse" + "$ref": "#/components/schemas/DocumentsListResponse" } } } }, "401": { "description": "Authentication required" - }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection or schedule not found" } } - } - }, - "/api/v1/connection-environments": { - "get": { - "operationId": "connectionEnvironmentsList", - "summary": "List connection environments", + }, + "post": { + "operationId": "documentsCreate", + "summary": "Create document", "tags": [ - "Connections" + "Documents" ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateBody" + } + } + } + }, "responses": { - "200": { - "description": "List of connection environments", + "201": { + "description": "Document created successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "List of connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "List connection environments response", - "title": "ConnectionsEnvironmentsListResponse" + "$ref": "#/components/schemas/DocumentsCreateResponse" } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied" + }, + "404": { + "description": "Model or branch not found" } } - }, - "post": { - "operationId": "connectionEnvironmentsCreate", - "summary": "Create connection environments", + } + }, + "/api/v1/documents/{identifier}": { + "get": { + "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", + "operationId": "documentsGet", + "summary": "Get document", "tags": [ - "Connections" + "Documents" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "environmentConnectionIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "IDs of connections to use as environments", - "example": [ - "550e8400-e29b-41d4-a716-446655440002", - "550e8400-e29b-41d4-a716-446655440003" - ] - } - }, - "required": [ - "baseConnectionId", - "environmentConnectionIds" - ], - "description": "Request body for creating connection environments", - "title": "ConnectionsEnvironmentsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Connection environments created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "Created connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "Create connection environments response", - "title": "ConnectionsEnvironmentsCreateResponse" + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Document details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetResponse" } } } }, "400": { - "description": "Invalid request body or connection IDs" + "description": "Analysis documents are not supported" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Insufficient permissions to view the document" }, "404": { - "description": "Base connection or environment connection not found" + "description": "Document not found" } } - } - }, - "/api/v1/connection-environments/{id}": { + }, "put": { - "operationId": "connectionEnvironmentsUpdate", - "summary": "Update connection environment", + "description": "Updates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", + "operationId": "documentsPut", + "summary": "Replace document (full replacement)", "tags": [ - "Connections" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Connection environment ID", - "name": "id", + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", "in": "path" } ], @@ -10912,577 +34119,506 @@ "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "userAttributeValues" - ], - "description": "Request body for updating a connection environment", - "title": "ConnectionsEnvironmentsUpdateBody" + "$ref": "#/components/schemas/DocumentsPutBody" } } } }, "responses": { "200": { - "description": "Connection environment updated successfully", + "description": "Document replaced successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Update connection environment response", - "title": "ConnectionsEnvironmentsUpdateResponse" + "$ref": "#/components/schemas/DocumentsPutResponse" } } } }, "400": { - "description": "Invalid request body" + "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Insufficient permissions to update the document" }, "404": { - "description": "Connection environment not found" + "description": "Document not found" + }, + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } }, - "delete": { - "operationId": "connectionEnvironmentsDelete", - "summary": "Delete connection environment", + "patch": { + "description": "Updates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", + "operationId": "documentsUpdate", + "summary": "Rename document", "tags": [ - "Connections" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Connection environment ID", - "name": "id", + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "Connection environment deleted successfully", + "description": "Document updated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete connection environment response", - "title": "ConnectionsEnvironmentsDeleteResponse" + "$ref": "#/components/schemas/DocumentsUpdateResponse" } } } }, + "400": { + "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - EDITOR role required" }, "404": { - "description": "Connection environment not found" + "description": "Document not found" + }, + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } - } - }, - "/api/v1/content": { - "get": { - "operationId": "contentList", - "summary": "List content", + }, + "delete": { + "operationId": "documentsDelete", + "summary": "Delete document", "tags": [ - "Content" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "number", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by creator user ID" - }, - "required": false, - "description": "Filter by creator user ID", - "name": "creatorId", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by folder ID (cannot be used with path)" - }, - "required": false, - "description": "Filter by folder ID (cannot be used with path)", - "name": "folderId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of fields to include (e.g., _count,labels)" - }, - "required": false, - "description": "Comma-separated list of fields to include (e.g., _count,labels)", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by folder path (cannot be used with folderId)", - "example": "/reports/sales" - }, - "required": false, - "description": "Filter by folder path (cannot be used with folderId)", - "name": "path", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Filter by share scope", - "example": "organization" - }, - "required": false, - "description": "Filter by share scope", - "name": "scope", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "description": "Sort direction", - "example": "asc" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "favorites" - ], - "description": "Field to sort by", - "example": "name" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], "responses": { "200": { - "description": "List of content (documents and folders)", + "description": "Document deleted successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ContentListResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, - "400": { - "description": "Invalid query parameters (cannot use both folderId and path)" - }, "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - MANAGER role required" + }, "404": { - "description": "Folder not found (when filtering by path)" + "description": "Document not found" } } } }, - "/api/v1/dashboards/{identifier}/download": { - "post": { - "operationId": "dashboardsDownload", - "summary": "Initiate dashboard download", + "/api/v1/documents/{identifier}/queries": { + "get": { + "operationId": "documentsGetQueries", + "summary": "List document queries", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + } + ], + "responses": { + "200": { + "description": "List of queries in the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetQueriesResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied" }, + "404": { + "description": "Document not found" + } + } + } + }, + "/api/v1/documents/{identifier}/move": { + "put": { + "operationId": "documentsMove", + "summary": "Move document", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsDownloadBody" + "$ref": "#/components/schemas/DocumentsMoveBody" } } } }, "responses": { "200": { - "description": "Download job initiated successfully", + "description": "Document moved successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsDownloadResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body or filter configuration" + "description": "Invalid folder path or scope" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - cannot download this dashboard" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Dashboard not found" - }, - "409": { - "description": "Download already in progress for this dashboard" - }, - "500": { - "description": "Failed to initiate download" + "description": "Document or folder not found" } } } }, - "/api/v1/dashboards/{identifier}/download/{jobId}": { + "/api/v1/documents/{identifier}/permissions": { "get": { - "operationId": "dashboardsDownloadFile", - "summary": "Get download file", + "operationId": "documentsGetPermissions", + "summary": "Get document permissions", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" }, { "schema": { "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" + "format": "uuid", + "description": "User membership ID to check permissions for" }, "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", + "description": "User membership ID to check permissions for", "name": "userId", "in": "query" } ], "responses": { "200": { - "description": "File ready - binary content streamed" - }, - "202": { - "description": "Download job still in progress" + "description": "User permissions for the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" + } + } + } }, "401": { "description": "Authentication required" }, - "404": { - "description": "Dashboard or download job not found" - }, - "410": { - "description": "Download job failed" + "403": { + "description": "Permission denied" }, - "500": { - "description": "Failed to retrieve download artifact" + "404": { + "description": "Document or user not found" } } - } - }, - "/api/v1/dashboards/{identifier}/download/{jobId}/status": { - "get": { - "operationId": "dashboardsDownloadStatus", - "summary": "Get download job status", + }, + "put": { + "operationId": "documentsUpdatePermissionSettings", + "summary": "Update document permission settings", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Permission settings updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" }, + "404": { + "description": "Document not found" + } + } + }, + "post": { + "operationId": "documentsAddPermits", + "summary": "Add document permits", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsAddPermitsBody" + } + } + } + }, "responses": { "200": { - "description": "Download job status" + "description": "Permissions added successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } + }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - MANAGER role required" + }, "404": { - "description": "Dashboard or download job not found" + "description": "Document not found" } } - } - }, - "/api/v1/dashboards/{identifier}/filters": { - "get": { - "operationId": "dashboardsGetFilters", - "summary": "Get dashboard filters", + }, + "patch": { + "operationId": "documentsUpdatePermits", + "summary": "Update document permits", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" + } + } + } + }, "responses": { "200": { - "description": "Dashboard filter and control configuration", + "description": "Permissions updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, + "400": { + "description": "Invalid request body - userIds or userGroupIds required" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - VIEWER role required" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Dashboard not found" + "description": "Document not found" } } }, - "patch": { - "operationId": "dashboardsUpdateFilters", - "summary": "Update dashboard filters", + "delete": { + "operationId": "documentsRevokePermits", + "summary": "Revoke document permits", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" + "$ref": "#/components/schemas/DocumentsRevokePermitsBody" } } } }, "responses": { "200": { - "description": "Filters updated successfully", + "description": "Permissions revoked successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body - must include at least one filter, control, or filterOrder" + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Dashboard not found or document does not have a dashboard" - }, - "409": { - "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." + "description": "Document not found" } } } }, - "/api/v1/documents": { - "get": { - "operationId": "documentsList", - "summary": "List documents", + "/api/v1/documents/{identifier}/draft": { + "post": { + "operationId": "documentsCreateDraft", + "summary": "Create document draft", "tags": [ "Documents" ], @@ -11490,158 +34626,88 @@ { "schema": { "type": "string", - "format": "uuid", - "description": "Filter by creator membership ID" - }, - "required": false, - "description": "Filter by creator membership ID", - "name": "creatorId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination" - }, - "required": false, - "description": "Cursor for pagination", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter by folder ID" - }, - "required": false, - "description": "Filter by folder ID", - "name": "folderId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "example": "_count,labels" - }, - "required": false, - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of label names to filter by", - "example": "verified,important" - }, - "required": false, - "description": "Comma-separated list of label names to filter by", - "name": "labels", - "in": "query" - }, - { - "schema": { - "type": "integer", - "exclusiveMinimum": 0, - "default": 50, - "description": "Number of records per page" - }, - "required": false, - "description": "Number of records per page", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "favorites", - "updatedAt", - "visits" - ], - "default": "name", - "description": "Field to sort by" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Filter documents visible to this membership ID" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Filter documents visible to this membership ID", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateDraftBody" + } + } + } + }, "responses": { "200": { - "description": "Paginated list of documents", + "description": "Draft created or existing draft returned", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsListResponse" + "$ref": "#/components/schemas/DocumentsCreateDraftResponse" } } } }, + "400": { + "description": "Document is not eligible for publishing workflow" + }, "401": { "description": "Authentication required" + }, + "403": { + "description": "Permission denied - EDITOR role required" + }, + "404": { + "description": "Document or branch not found" } } }, - "post": { - "operationId": "documentsCreate", - "summary": "Create document", + "delete": { + "operationId": "documentsDiscardDraft", + "summary": "Discard document draft", "tags": [ "Documents" ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateBody" + "$ref": "#/components/schemas/DocumentsDiscardDraftBody" } } } }, "responses": { - "201": { - "description": "Document created successfully", + "200": { + "description": "Draft discarded successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateResponse" + "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" } } } }, - "400": { - "description": "Invalid request body" - }, "401": { "description": "Authentication required" }, @@ -11649,16 +34715,16 @@ "description": "Permission denied" }, "404": { - "description": "Model or branch not found" + "description": "Document or draft not found" } } } }, - "/api/v1/documents/{identifier}": { - "get": { - "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", - "operationId": "documentsGet", - "summary": "Get document", + "/api/v1/documents/{identifier}/drafts": { + "get": { + "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", + "operationId": "documentsListDrafts", + "summary": "List document drafts", "tags": [ "Documents" ], @@ -11673,21 +34739,32 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "example": "archived" + }, + "required": false, + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "name": "include", + "in": "query" } ], "responses": { "200": { - "description": "Document details", + "description": "List of drafts for the document", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsGetResponse" + "$ref": "#/components/schemas/DocumentsListDraftsResponse" } } } }, "400": { - "description": "Analysis documents are not supported" + "description": "Invalid query parameters" }, "401": { "description": "Authentication required" @@ -11699,11 +34776,12 @@ "description": "Document not found" } } - }, - "put": { - "description": "Updates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", - "operationId": "documentsPut", - "summary": "Replace document (full replacement)", + } + }, + "/api/v1/documents/{identifier}/duplicate": { + "post": { + "operationId": "documentsDuplicate", + "summary": "Duplicate document", "tags": [ "Documents" ], @@ -11718,49 +34796,58 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsPutBody" + "$ref": "#/components/schemas/DocumentsDuplicateBody" } } } }, "responses": { - "200": { - "description": "Document replaced successfully", + "201": { + "description": "Document duplicated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsPutResponse" + "$ref": "#/components/schemas/DocumentsDuplicateResponse" } } } }, "400": { - "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" + "description": "Invalid name or folder path" }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions to update the document" + "description": "Permission denied" }, "404": { - "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" + "description": "Document or folder not found" } } - }, - "patch": { - "description": "Updates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", - "operationId": "documentsUpdate", - "summary": "Rename document", + } + }, + "/api/v1/documents/{identifier}/favorite": { + "put": { + "operationId": "documentsAddFavorite", + "summary": "Add document to favorites", "tags": [ "Documents" ], @@ -11775,48 +34862,37 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdateBody" - } - } - } - }, "responses": { - "200": { - "description": "Document updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" + "204": { + "description": "Favorite added successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Permission denied" }, "404": { "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } }, "delete": { - "operationId": "documentsDelete", - "summary": "Delete document", + "operationId": "documentsRemoveFavorite", + "summary": "Remove document from favorites", "tags": [ "Documents" ], @@ -11831,24 +34907,28 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "responses": { - "200": { - "description": "Document deleted successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } + "204": { + "description": "Favorite removed successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document not found" @@ -11856,10 +34936,10 @@ } } }, - "/api/v1/documents/{identifier}/queries": { - "get": { - "operationId": "documentsGetQueries", - "summary": "List document queries", + "/api/v1/documents/{identifier}/labels": { + "patch": { + "operationId": "documentsBulkUpdateLabels", + "summary": "Bulk update document labels", "tags": [ "Documents" ], @@ -11874,19 +34954,42 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" + } + } + } + }, "responses": { "200": { - "description": "List of queries in the document", + "description": "Labels updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsGetQueriesResponse" + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" } } } }, + "400": { + "description": "Invalid request - at least one label must be specified" + }, "401": { "description": "Authentication required" }, @@ -11899,10 +35002,10 @@ } } }, - "/api/v1/documents/{identifier}/move": { - "post": { - "operationId": "documentsMove", - "summary": "Move document", + "/api/v1/documents/{identifier}/labels/{labelName}": { + "put": { + "operationId": "documentsAddLabel", + "summary": "Add label to document", "tags": [ "Documents" ], @@ -11910,54 +35013,55 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsMoveBody" - } - } - } - }, "responses": { - "200": { - "description": "Document moved successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid folder path or scope" + "204": { + "description": "Label added successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { - "description": "Document or folder not found" + "description": "Document or label not found" } } - } - }, - "/api/v1/documents/{identifier}/permissions": { - "get": { - "operationId": "documentsGetPermissions", - "summary": "Get document permissions", + }, + "delete": { + "operationId": "documentsRemoveLabel", + "summary": "Remove label from document", "tags": [ "Documents" ], @@ -11965,36 +35069,40 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "name": "identifier", "in": "path" }, { "schema": { "type": "string", - "format": "uuid", - "description": "User membership ID to check permissions for" + "description": "Label name", + "example": "verified" }, "required": true, - "description": "User membership ID to check permissions for", + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", "name": "userId", "in": "query" } ], "responses": { - "200": { - "description": "User permissions for the document", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" - } - } - } + "204": { + "description": "Label removed successfully" }, "401": { "description": "Authentication required" @@ -12003,13 +35111,15 @@ "description": "Permission denied" }, "404": { - "description": "Document or user not found" + "description": "Document not found" } } - }, + } + }, + "/api/v1/documents/{identifier}/transfer-ownership": { "put": { - "operationId": "documentsUpdatePermissionSettings", - "summary": "Update document permission settings", + "operationId": "documentsTransferOwnership", + "summary": "Transfer document ownership", "tags": [ "Documents" ], @@ -12030,14 +35140,14 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" + "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" } } } }, "responses": { "200": { - "description": "Permission settings updated successfully", + "description": "Ownership transferred successfully", "content": { "application/json": { "schema": { @@ -12047,22 +35157,24 @@ } }, "400": { - "description": "Invalid request body" + "description": "Invalid user ID" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied - MANAGER role or owner required" }, "404": { - "description": "Document not found" + "description": "Document or user not found" } } - }, - "post": { - "operationId": "documentsAddPermits", - "summary": "Add document permits", + } + }, + "/api/v1/documents/{identifier}/access-list": { + "get": { + "operationId": "documentsAccessList", + "summary": "List document access principals", "tags": [ "Documents" ], @@ -12077,45 +35189,115 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction (default: asc)", + "example": "desc" + }, + "required": false, + "description": "Sort direction (default: asc)", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "direct", + "folder" + ], + "description": "Filter by access source: direct or folder" + }, + "required": false, + "description": "Filter by access source: direct or folder", + "name": "accessSource", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "user", + "userGroup" + ], + "description": "Filter by principal type: user or userGroup" + }, + "required": false, + "description": "Filter by principal type: user or userGroup", + "name": "type", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsAddPermitsBody" - } - } - } - }, "responses": { "200": { - "description": "Permissions added successfully", + "description": "List of users and groups with access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsAccessListResponse" } } } }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied - VIEWER role required" }, "404": { "description": "Document not found" } } - }, - "patch": { - "operationId": "documentsUpdatePermits", - "summary": "Update document permits", + } + }, + "/api/v1/documents/{identifier}/favorites": { + "get": { + "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", + "operationId": "documentsListFavorites", + "summary": "List users who favorited the document", "tags": [ "Documents" ], @@ -12130,45 +35312,127 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "example": "desc" + }, + "required": false, + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "name": "sortDirection", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of users who favorited the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsListFavoritesResponse" + } + } + } + }, + "400": { + "description": "Invalid query parameters" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied — caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" + }, + "404": { + "description": "Document not found" } + } + } + }, + "/api/v2/documents": { + "post": { + "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to existing content).", + "operationId": "documentsV2Create", + "summary": "Create document", + "tags": [ + "Documents" ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" + "$ref": "#/components/schemas/DocumentsV2CreateBody" } } } }, "responses": { - "200": { - "description": "Permissions updated successfully", + "201": { + "description": "Document created and published successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsV2CreateResponse" } } } }, "400": { - "description": "Invalid request body - userIds or userGroupIds required" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Insufficient permissions to create a document on this model." }, "404": { - "description": "Document not found" + "description": "Base model or branch not found." + }, + "405": { + "description": "Method not allowed." } } - }, - "delete": { - "operationId": "documentsRevokePermits", - "summary": "Revoke document permits", + } + }, + "/api/v2/documents/{identifier}": { + "get": { + "description": "Read the document's current draft state (or the published state if no draft exists). Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2Get", + "summary": "Read document state", "tags": [ "Documents" ], @@ -12176,54 +35440,46 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsRevokePermitsBody" - } - } - } - }, "responses": { "200": { - "description": "Permissions revoked successfully", + "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsV2ReadResponse" } } } }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" - }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Insufficient permissions to read the document." }, "404": { - "description": "Document not found" + "description": "Document not found." + }, + "422": { + "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." } - } - } - }, - "/api/v1/documents/{identifier}/draft": { - "post": { - "operationId": "documentsCreateDraft", - "summary": "Create document draft", + } + } + }, + "/api/v2/documents/{identifier}/draft": { + "patch": { + "description": "Create a new draft on the published document and apply the patch. No auto-publish — the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", + "operationId": "documentsV2PatchDraft", + "summary": "Create draft and patch document", "tags": [ "Documents" ], @@ -12231,11 +35487,11 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" } @@ -12244,39 +35500,51 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftBody" + "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" } } } }, "responses": { "200": { - "description": "Draft created or existing draft returned", + "description": "Draft created and patch applied successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftResponse" + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" } } } }, "400": { - "description": "Document is not eligible for publishing workflow" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Insufficient permissions to update the document." }, "404": { - "description": "Document or branch not found" + "description": "Document or branch not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." } } - }, - "delete": { - "operationId": "documentsDiscardDraft", - "summary": "Discard document draft", + } + }, + "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { + "get": { + "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2GetDraft", + "summary": "Read draft state", "tags": [ "Documents" ], @@ -12284,51 +35552,55 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" + }, + "required": true, + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Published document identifier.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Published document identifier.", "name": "identifier", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftBody" - } - } - } - }, "responses": { "200": { - "description": "Draft discarded successfully", + "description": "Draft state.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" + "$ref": "#/components/schemas/DocumentsV2ReadResponse" } } } }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to read the draft." }, "404": { - "description": "Document or draft not found" + "description": "Document or draft not found." + }, + "422": { + "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." } } - } - }, - "/api/v1/documents/{identifier}/duplicate": { - "post": { - "operationId": "documentsDuplicate", - "summary": "Duplicate document", + }, + "patch": { + "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, no publish.", + "operationId": "documentsV2PatchDraftByIdentifier", + "summary": "Patch draft", "tags": [ "Documents" ], @@ -12336,65 +35608,75 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", "in": "path" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Published document identifier.", + "example": "abc123" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "description": "Published document identifier.", + "name": "identifier", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateBody" + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" } } } }, "responses": { - "201": { - "description": "Document duplicated successfully", + "200": { + "description": "Patch applied to draft successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateResponse" + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" } } } }, "400": { - "description": "Invalid name or folder path" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to update the draft." }, "404": { - "description": "Document or folder not found" + "description": "Document or draft not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." } } } }, - "/api/v1/documents/{identifier}/favorite": { - "put": { - "operationId": "documentsAddFavorite", - "summary": "Add document to favorites", + "/api/v2/documents/{identifier}/draft/publish": { + "post": { + "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body — the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", + "operationId": "documentsV2PublishDraft", + "summary": "Publish draft", "tags": [ "Documents" ], @@ -12402,479 +35684,565 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { - "204": { - "description": "Favorite added successfully" + "200": { + "description": "Draft published successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" + } + } + } + }, + "400": { + "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to publish the draft." }, "404": { - "description": "Document not found" + "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document." } } - }, - "delete": { - "operationId": "documentsRemoveFavorite", - "summary": "Remove document from favorites", + } + }, + "/api/v1/embed/sso/generate-session": { + "post": { + "operationId": "embedSsoGenerateSession", + "summary": "Generate embedded SSO session", "tags": [ - "Documents" + "Embed" ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" + } + } } - ], + }, "responses": { - "204": { - "description": "Favorite removed successfully" + "200": { + "description": "Session token generated", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" + } + } + } + }, + "400": { + "description": "Invalid request body" }, "401": { - "description": "Authentication required" + "description": "Authentication required (API key with embed scope)" }, "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" + "description": "Permission denied - embed not enabled" } } } }, - "/api/v1/documents/{identifier}/labels": { - "patch": { - "operationId": "documentsBulkUpdateLabels", - "summary": "Bulk update document labels", + "/api/v1/ai/eval/prompt-sets": { + "get": { + "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", + "operationId": "aiEvalPromptSetsList", + "summary": "List eval prompt sets", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" + "enum": [ + "true", + "false" + ], + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "example": "false" }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" + "required": false, + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "name": "archived", + "in": "query" }, { "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." }, "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", + "name": "model_ids", "in": "query" } ], + "responses": { + "200": { + "description": "List of prompt sets, sorted alphabetically by name.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsListResponse" + } + } + } + }, + "400": { + "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "No eval-accessible models for this caller.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + } + } + }, + "post": { + "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", + "operationId": "aiEvalPromptSetsCreate", + "summary": "Create an eval prompt set", + "tags": [ + "AI Eval" + ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" + "$ref": "#/components/schemas/EvalPromptSetsCreateBody" } } } }, "responses": { - "200": { - "description": "Labels updated successfully", + "201": { + "description": "Prompt set created successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" + "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" } } } }, "400": { - "description": "Invalid request - at least one label must be specified" + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" + "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } } } } }, - "/api/v1/documents/{identifier}/labels/{labelName}": { - "put": { - "operationId": "documentsAddLabel", - "summary": "Add label to document", + "/api/v1/ai/eval/prompt-sets/{promptSetId}": { + "get": { + "description": "Get a single prompt set with all of its prompts.", + "operationId": "aiEvalPromptSetsGet", + "summary": "Get an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "required": true, - "description": "Document identifier", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Label name", - "name": "labelName", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { - "204": { - "description": "Label added successfully" + "200": { + "description": "Prompt set details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsGetResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document or label not found" + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } } } }, - "delete": { - "operationId": "documentsRemoveLabel", - "summary": "Remove label from document", + "patch": { + "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list — existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", + "operationId": "aiEvalPromptSetsUpdate", + "summary": "Update an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "required": true, - "description": "Document identifier", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "required": true, - "description": "Label name", - "name": "labelName", - "in": "path" - }, { "schema": { "type": "string", "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Label removed successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/transfer-ownership": { - "put": { - "operationId": "documentsTransferOwnership", - "summary": "Transfer document ownership", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" + "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" } } } }, "responses": { "200": { - "description": "Ownership transferred successfully", + "description": "Prompt set updated successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" } } } }, "400": { - "description": "Invalid user ID" + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - MANAGER role or owner required" - }, - "404": { - "description": "Document or user not found" - } - } - } - }, - "/api/v1/documents/{identifier}/access-list": { - "get": { - "operationId": "documentsAccessList", - "summary": "List document access principals", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "number", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction (default: asc)", - "example": "desc" - }, - "required": false, - "description": "Sort direction (default: asc)", - "name": "sortDirection", - "in": "query" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, - { - "schema": { - "type": "string", - "description": "Field to sort results by" - }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, - { - "schema": { - "type": "string", - "enum": [ - "direct", - "folder" - ], - "description": "Filter by access source: direct or folder" - }, - "required": false, - "description": "Filter by access source: direct or folder", - "name": "accessSource", - "in": "query" + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } }, + "422": { + "description": "A `prompts[].id` in the request does not belong to this prompt set.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + } + } + }, + "delete": { + "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent — retrying drains any remaining runs.", + "operationId": "aiEvalPromptSetsArchive", + "summary": "Archive an eval prompt set", + "tags": [ + "AI Eval" + ], + "parameters": [ { "schema": { "type": "string", - "enum": [ - "user", - "userGroup" - ], - "description": "Filter by principal type: user or userGroup" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Filter by principal type: user or userGroup", - "name": "type", - "in": "query" + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" } ], "responses": { "200": { - "description": "List of users and groups with access", + "description": "Prompt set archived successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsAccessListResponse" + "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" } } } }, "401": { - "description": "Authentication required" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied - VIEWER role required" + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document not found" + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "500": { + "description": "Archive committed but a run-cancellation failed; the set is already archived — safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } } } } }, - "/api/v1/embed/sso/generate-session": { + "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { "post": { - "operationId": "embedSsoGenerateSession", - "summary": "Generate embedded SSO session", + "description": "Restore an archived prompt set.", + "operationId": "aiEvalPromptSetsUnarchive", + "summary": "Restore an archived eval prompt set", "tags": [ - "Embed" + "AI Eval" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" - } - } + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", + "in": "path" } - }, + ], "responses": { "200": { - "description": "Session token generated", + "description": "Prompt set restored successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" + "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" } } } }, "400": { - "description": "Invalid request body" + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required (API key with embed scope)" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied - embed not enabled" + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } + }, + "404": { + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } } } } @@ -13437,6 +36805,7 @@ { "schema": { "type": "string", + "format": "uuid", "description": "Target user membership ID (for org-scoped API keys)" }, "required": false, @@ -13540,6 +36909,7 @@ { "schema": { "type": "string", + "format": "uuid", "description": "Target user membership ID (for org-scoped API keys)" }, "required": false, @@ -13606,6 +36976,7 @@ { "schema": { "type": "string", + "format": "uuid", "description": "Target user membership ID (for org-scoped API keys)" }, "required": false, @@ -14811,6 +38182,43 @@ "description": "Branch ID for branch-based schema refresh. Required when branch-based schema refresh is enabled for the connection. Must not be provided when branch-based schema refresh is not enabled.", "name": "branch_id", "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "true", + "false" + ], + "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", + "example": "false" + }, + "required": false, + "description": "When true (the default), performs a hard refresh that fully discards and rebuilds the schema model. When false, performs a soft refresh that merges newly generated views with the existing model. Must be set to false when `schemas` or `tables` filters are provided.", + "name": "hard_refresh", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "example": "public,analytics" + }, + "required": false, + "description": "Optional comma-separated list of schemas to refresh selectively. Only the listed schemas are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "name": "schemas", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "example": "public.orders,public.customers" + }, + "required": false, + "description": "Optional comma-separated list of tables to refresh selectively. Only the listed tables are reloaded; the rest of the schema model is preserved. Requires `hard_refresh=false`.", + "name": "tables", + "in": "query" } ], "responses": { @@ -14825,7 +38233,7 @@ } }, "400": { - "description": "Bad request - branch_id required when branch-based schema refresh is enabled, or branch_id not allowed when it is not enabled" + "description": "Bad request - branch_id required when branch-based schema refresh is enabled, branch_id not allowed when it is not enabled, or hard refresh requested with selective schemas/tables filters" }, "401": { "description": "Authentication required" @@ -15050,15 +38458,15 @@ }, { "schema": { - "type": "number", + "type": "integer", "minimum": 1, "maximum": 100, "default": 20, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "example": 20 }, "required": false, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "name": "pageSize", "in": "query" }, @@ -15688,6 +39096,17 @@ "name": "content_filter_mode", "in": "query" }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter to documents created by this user (user ID). Unknown IDs return 400." + }, + "required": false, + "description": "Filter to documents created by this user (user ID). Unknown IDs return 400.", + "name": "creator_id", + "in": "query" + }, { "schema": { "type": "string", @@ -15805,6 +39224,7 @@ { "schema": { "type": "string", + "format": "uuid", "description": "Target user membership ID (for org-scoped API keys)" }, "required": false, @@ -15897,7 +39317,7 @@ "extension", "staged", "merged", - "history" + "fully-resolved" ], "default": "combined", "description": "IDE mode for YAML operations" @@ -16084,7 +39504,7 @@ "extension", "staged", "merged", - "history" + "fully-resolved" ], "default": "combined", "description": "IDE mode for YAML operations" @@ -16124,6 +39544,51 @@ } } }, + "/api/v1/models/{modelId}/ai-agent-actions": { + "get": { + "description": "Returns the AI agent actions configured for this model — a unified list of sample queries and skills suitable for surfacing as suggested prompts above an AI prompt input. Sample queries come from both `model.sample_queries` and each topic's `sample_queries`; skills come from `model.skills` and each topic's `skills`, deduped by id with topic skills overriding model skills. Each entry's `prompt` is ready to submit verbatim to `POST /api/v1/ai/jobs`.", + "operationId": "modelAiAgentActions", + "summary": "Get model AI agent actions", + "tags": [ + "Models" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Model UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Model UUID", + "name": "modelId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "AI agent actions in display order.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiAgentActionsResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key." + }, + "403": { + "description": "Caller cannot read the model." + }, + "404": { + "description": "Model not found." + } + } + } + }, "/api/v1/query/run": { "post": { "operationId": "queryRun", @@ -16131,6 +39596,19 @@ "tags": [ "Query" ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], "requestBody": { "content": { "application/json": { @@ -16248,15 +39726,15 @@ }, { "schema": { - "type": "number", + "type": "integer", "minimum": 1, "maximum": 100, "default": 20, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "example": 20 }, "required": false, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "name": "pageSize", "in": "query" }, @@ -17118,7 +40596,7 @@ "description": "Schedule not found" }, "409": { - "description": "Another execution is in progress for this schedule" + "description": "Schedule cannot be triggered (paused, system-disabled, or another execution is in progress)" } } } @@ -18026,15 +41504,15 @@ }, { "schema": { - "type": "number", + "type": "integer", "minimum": 1, "maximum": 100, "default": 20, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "example": 20 }, "required": false, - "description": "Number of results per page (1-100)", + "description": "Number of results per page (1-100, integer)", "name": "pageSize", "in": "query" }, diff --git a/internal/openapi/body_shorthand.go b/internal/openapi/body_shorthand.go index 99b7b77..9b2d5f5 100644 --- a/internal/openapi/body_shorthand.go +++ b/internal/openapi/body_shorthand.go @@ -202,6 +202,44 @@ var bodyShorthands = map[string]*BodyShorthand{ ExampleShort: `omni models git-sync --commit-message "Update schema"`, ExampleJSON: `omni models git-sync --body '{"commitMessage":"Update schema"}'`, }, + + // v2 documents. Metadata fields are promoted to flags; the heavy nested + // content (containers / controls / queryPresentations / settings) stays + // on --body/stdin. Because a v2-get response is a valid draft PATCH body, + // content round-trips cleanly: v2-get > doc.json, edit, then + // v2-patch-draft --body - < doc.json and v2-publish-draft . + "documentsV2Create": { + Args: []ArgMapping{ + {Name: "model-id", FieldPath: "modelId", Description: "UUID of the model the document is built on", Transform: "string"}, + {Name: "name", FieldPath: "name", Description: "name for the new document", Transform: "string"}, + }, + Flags: []FlagMapping{ + {FlagName: "identifier", FieldPath: "identifier", Description: "identifier for the new document (server-minted if omitted)"}, + {FlagName: "description", FieldPath: "description", Description: "document description"}, + {FlagName: "folder-id", FieldPath: "folderId", Description: "destination folder ID (omit for the root folder)"}, + }, + ExampleShort: `omni documents v2-create 770e8400-e29b-41d4-a716-446655440002 "Q3 Revenue"`, + ExampleJSON: `omni documents v2-create --body '{"modelId":"770e8400-...","name":"Q3 Revenue"}'`, + }, + "documentsV2PatchDraft": { + Flags: []FlagMapping{ + {FlagName: "name", FieldPath: "name", Description: "document name"}, + {FlagName: "description", FieldPath: "description", Description: "document description"}, + {FlagName: "summary", FieldPath: "summary", Description: "what this patch changes; written to the history audit trail"}, + {FlagName: "branch-id", FieldPath: "branchId", Description: "branch the new draft is created on (omit for the main workspace)"}, + }, + ExampleShort: `omni documents v2-patch-draft --name "WIP title"`, + ExampleJSON: `omni documents v2-patch-draft --body '{"name":"WIP title"}'`, + }, + "documentsV2PatchDraftByIdentifier": { + Flags: []FlagMapping{ + {FlagName: "name", FieldPath: "name", Description: "document name"}, + {FlagName: "description", FieldPath: "description", Description: "document description"}, + {FlagName: "summary", FieldPath: "summary", Description: "what this patch changes; written to the history audit trail"}, + }, + ExampleShort: `omni documents v2-patch-draft-by-identifier --name "Edited"`, + ExampleJSON: `omni documents v2-patch-draft-by-identifier --body '{"name":"Edited"}'`, + }, } // GetBodyShorthand returns the shorthand for an operation, or nil if none exists. @@ -323,16 +361,14 @@ func assembleBody(sh *BodyShorthand, args []string, pathParamCount int, cmd *cob } for _, fm := range sh.Flags { + val, _ := cmd.Flags().GetString(fm.FlagName) + if val == "" { + continue + } if fm.IsBool { - val, _ := cmd.Flags().GetString(fm.FlagName) - if val != "" { - body[fm.FieldPath] = (val == "true") - } + body[fm.FieldPath] = (val == "true") } else { - val, _ := cmd.Flags().GetString(fm.FlagName) - if val != "" { - body[fm.FieldPath] = val - } + body[fm.FieldPath] = val } } diff --git a/internal/openapi/body_shorthand_test.go b/internal/openapi/body_shorthand_test.go index dbae591..a879720 100644 --- a/internal/openapi/body_shorthand_test.go +++ b/internal/openapi/body_shorthand_test.go @@ -534,6 +534,104 @@ func TestShorthand_ModelsGitSync_FlagsOnly(t *testing.T) { } } +func TestShorthand_DocumentsV2Create(t *testing.T) { + var captured APIRequest + exec := func(req APIRequest) error { captured = req; return nil } + + op := &operationInfo{ + Tag: "Documents", + OperationID: "documentsV2Create", + Method: "POST", + Path: "/api/v2/documents", + HasBody: true, + } + + cmd := buildCommand(op, exec) + cmd.SetArgs([]string{"770e8400-e29b-41d4-a716-446655440002", "Q3 Revenue", "--folder-id", "f-1", "--identifier", "q3-rev"}) + if err := cmd.Execute(); err != nil { + t.Fatalf("Execute: %v", err) + } + + var body map[string]interface{} + if err := json.Unmarshal(captured.Body, &body); err != nil { + t.Fatalf("unmarshal body: %v", err) + } + if body["modelId"] != "770e8400-e29b-41d4-a716-446655440002" { + t.Errorf("modelId = %v, want the positional model ID", body["modelId"]) + } + if body["name"] != "Q3 Revenue" { + t.Errorf("name = %v, want 'Q3 Revenue'", body["name"]) + } + if body["folderId"] != "f-1" { + t.Errorf("folderId = %v, want f-1", body["folderId"]) + } + if body["identifier"] != "q3-rev" { + t.Errorf("identifier = %v, want q3-rev", body["identifier"]) + } +} + +func TestShorthand_DocumentsV2PatchDraft(t *testing.T) { + var captured APIRequest + exec := func(req APIRequest) error { captured = req; return nil } + + op := &operationInfo{ + Tag: "Documents", + OperationID: "documentsV2PatchDraft", + Method: "PATCH", + Path: "/api/v2/documents/{identifier}/draft", + PathParams: []paramInfo{{Name: "identifier", In: "path"}}, + HasBody: true, + } + + cmd := buildCommand(op, exec) + cmd.SetArgs([]string{"abc123", "--name", "WIP", "--branch-id", "b-1"}) + if err := cmd.Execute(); err != nil { + t.Fatalf("Execute: %v", err) + } + + var body map[string]interface{} + json.Unmarshal(captured.Body, &body) + if body["name"] != "WIP" { + t.Errorf("name = %v, want WIP", body["name"]) + } + if body["branchId"] != "b-1" { + t.Errorf("branchId = %v, want b-1", body["branchId"]) + } +} + +func TestShorthand_DocumentsV2PatchDraftByIdentifier(t *testing.T) { + var captured APIRequest + exec := func(req APIRequest) error { captured = req; return nil } + + op := &operationInfo{ + Tag: "Documents", + OperationID: "documentsV2PatchDraftByIdentifier", + Method: "PATCH", + Path: "/api/v2/documents/{identifier}/draft/{draftIdentifier}", + PathParams: []paramInfo{{Name: "identifier", In: "path"}, {Name: "draftIdentifier", In: "path"}}, + HasBody: true, + } + + cmd := buildCommand(op, exec) + cmd.SetArgs([]string{"abc123", "draft456", "--name", "Edited"}) + if err := cmd.Execute(); err != nil { + t.Fatalf("Execute: %v", err) + } + + if !strings.Contains(captured.Path, "abc123") || !strings.Contains(captured.Path, "draft456") { + t.Errorf("path = %q, expected to contain both identifiers", captured.Path) + } + + var body map[string]interface{} + json.Unmarshal(captured.Body, &body) + if body["name"] != "Edited" { + t.Errorf("name = %v, want Edited", body["name"]) + } + if _, exists := body["draftIdentifier"]; exists { + t.Error("path param draftIdentifier should not appear in body") + } +} + // --------------------------------------------------------------------------- // Fallback / alias tests // @@ -722,8 +820,8 @@ func TestShorthand_RegistryNotEmpty(t *testing.T) { if len(bodyShorthands) == 0 { t.Fatal("bodyShorthands registry is empty") } - if len(bodyShorthands) != 16 { - t.Errorf("expected 16 shorthand entries, got %d", len(bodyShorthands)) + if len(bodyShorthands) != 19 { + t.Errorf("expected 19 shorthand entries, got %d", len(bodyShorthands)) } } From a810272783e934b185c9465994b61dae5eb927ba Mon Sep 17 00:00:00 2001 From: Daniel Spangenberger Date: Fri, 12 Jun 2026 16:28:05 -0400 Subject: [PATCH 2/4] fix: order positional args by URL path order, not spec parameter order The v2 document draft routes declare draftIdentifier before identifier in the spec's parameters array, so generated commands took args in the reverse of the URL shape (v2-get-draft ), 404ing for anyone following the documented order. Sort path params by their position in the path template; only the two draft-by-identifier commands change. Co-Authored-By: Claude Fable 5 --- internal/openapi/generate.go | 7 +++++ internal/openapi/generate_test.go | 48 +++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/internal/openapi/generate.go b/internal/openapi/generate.go index deaa1f7..2eb218b 100644 --- a/internal/openapi/generate.go +++ b/internal/openapi/generate.go @@ -147,6 +147,13 @@ func extractOperations(pathStr string, item *v3.PathItem, groups map[string][]*o } } + // Positional args follow the URL shape, not the spec's parameters + // array — some endpoints declare path params out of path order. + sort.SliceStable(info.PathParams, func(i, j int) bool { + return strings.Index(pathStr, "{"+info.PathParams[i].Name+"}") < + strings.Index(pathStr, "{"+info.PathParams[j].Name+"}") + }) + // Check for request body if op.RequestBody != nil { info.HasBody = true diff --git a/internal/openapi/generate_test.go b/internal/openapi/generate_test.go index 262d607..c0b8f2d 100644 --- a/internal/openapi/generate_test.go +++ b/internal/openapi/generate_test.go @@ -228,6 +228,54 @@ func TestGenerateCommandsFromSpec(t *testing.T) { } } +// Some endpoints declare path params in the spec's parameters array in a +// different order than they appear in the URL (e.g. the v2 document draft +// routes list draftIdentifier before identifier). Positional args must follow +// the URL shape, so a generated command's arg order matches the path template +// regardless of declaration order. +func TestGenerateCommands_PathParamsFollowPathOrder(t *testing.T) { + spec := `{ + "openapi": "3.1.0", + "info": {"title": "test", "version": "1.0"}, + "paths": { + "/api/v1/things/{outerId}/items/{innerId}": { + "get": { + "operationId": "testGetItem", + "tags": ["test"], + "parameters": [ + {"name": "innerId", "in": "path", "required": true, "schema": {"type": "string"}}, + {"name": "outerId", "in": "path", "required": true, "schema": {"type": "string"}} + ], + "responses": {"200": {"description": "ok"}} + } + } + } + }` + + var captured APIRequest + exec := func(req APIRequest) error { captured = req; return nil } + cmds, err := GenerateCommands([]byte(spec), exec) + if err != nil { + t.Fatalf("GenerateCommands: %v", err) + } + if len(cmds) != 1 || len(cmds[0].Commands()) != 1 { + t.Fatalf("expected 1 tag group with 1 subcommand, got %v", cmds) + } + + sub := cmds[0].Commands()[0] + if sub.Use != "get-item " { + t.Errorf("Use = %q, want %q", sub.Use, "get-item ") + } + + // Positional args in path order must substitute into the matching slots. + if err := sub.RunE(sub, []string{"outer-val", "inner-val"}); err != nil { + t.Fatalf("RunE: %v", err) + } + if captured.Path != "/api/v1/things/outer-val/items/inner-val" { + t.Errorf("path = %q, want %q", captured.Path, "/api/v1/things/outer-val/items/inner-val") + } +} + // --------------------------------------------------------------------------- // Command behavior tests // From fe147c2d2b9acbb5bfca993d4ab5fe8b9aecd2f3 Mon Sep 17 00:00:00 2001 From: Daniel Spangenberger Date: Fri, 12 Jun 2026 16:28:14 -0400 Subject: [PATCH 3/4] fix: reject shorthand flags combined with --body MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A non-empty --body short-circuited before shorthand assembly, silently dropping promoted flags like --branch-id — e.g. a draft PATCH meant for a branch landed on mainline. Fail fast instead, naming the conflicting flags. Uses Changed() so flag defaults don't false-positive, and covers the hidden --json-body alias. Co-Authored-By: Claude Fable 5 --- internal/openapi/body_shorthand.go | 13 +++++- internal/openapi/body_shorthand_test.go | 54 +++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/internal/openapi/body_shorthand.go b/internal/openapi/body_shorthand.go index 9b2d5f5..1cf1b55 100644 --- a/internal/openapi/body_shorthand.go +++ b/internal/openapi/body_shorthand.go @@ -277,8 +277,19 @@ func applyBodyShorthand(cmd *cobra.Command, op *operationInfo, sh *BodyShorthand rawBody = jsonBodyFlag } - // If --body/--json-body is provided, use existing behavior + // If --body/--json-body is provided, use existing behavior — but + // reject explicitly-set shorthand flags rather than silently + // dropping them from the request. if rawBody != "" { + var conflicting []string + for _, f := range sh.Flags { + if cmd.Flags().Changed(f.FlagName) { + conflicting = append(conflicting, "--"+f.FlagName) + } + } + if len(conflicting) > 0 { + return fmt.Errorf("%s cannot be combined with --body; include the field(s) in the JSON body instead", strings.Join(conflicting, ", ")) + } return originalRunE(cmd, args) } diff --git a/internal/openapi/body_shorthand_test.go b/internal/openapi/body_shorthand_test.go index a879720..05fde74 100644 --- a/internal/openapi/body_shorthand_test.go +++ b/internal/openapi/body_shorthand_test.go @@ -712,6 +712,60 @@ func TestShorthand_BothBodyFlagsError(t *testing.T) { } } +// Combining a promoted shorthand flag with --body is an error: the raw body +// is sent verbatim, so a silently-dropped flag (e.g. --branch-id) would +// produce a request the user didn't intend. +func TestShorthand_BodyWithShorthandFlagErrors(t *testing.T) { + exec := func(req APIRequest) error { return nil } + + op := &operationInfo{ + Tag: "Documents", + OperationID: "documentsV2PatchDraft", + Method: "PATCH", + Path: "/api/v2/documents/{identifier}/draft", + PathParams: []paramInfo{{Name: "identifier", In: "path"}}, + HasBody: true, + } + + cmd := buildCommand(op, exec) + cmd.SilenceUsage = true + cmd.SilenceErrors = true + cmd.SetArgs([]string{"doc-123", "--branch-id", "b-1", "--body", `{"name":"x"}`}) + err := cmd.Execute() + if err == nil { + t.Fatal("expected error when --branch-id is combined with --body") + } + if !strings.Contains(err.Error(), "--branch-id") { + t.Errorf("error = %q, want it to name --branch-id", err.Error()) + } +} + +// The conflict check also covers the hidden --json-body alias. +func TestShorthand_JsonBodyWithShorthandFlagErrors(t *testing.T) { + exec := func(req APIRequest) error { return nil } + + op := &operationInfo{ + Tag: "Documents", + OperationID: "documentsV2PatchDraft", + Method: "PATCH", + Path: "/api/v2/documents/{identifier}/draft", + PathParams: []paramInfo{{Name: "identifier", In: "path"}}, + HasBody: true, + } + + cmd := buildCommand(op, exec) + cmd.SilenceUsage = true + cmd.SilenceErrors = true + cmd.SetArgs([]string{"doc-123", "--summary", "s", "--json-body", `{"name":"x"}`}) + err := cmd.Execute() + if err == nil { + t.Fatal("expected error when --summary is combined with --json-body") + } + if !strings.Contains(err.Error(), "--summary") { + t.Errorf("error = %q, want it to name --summary", err.Error()) + } +} + // Verify that --body still works for operations with a shorthand when // the user provides path params + --body but no shorthand positional arg. func TestShorthand_BodyWithPathParams(t *testing.T) { From 8370d51c93c9118690313a71ac58fc3b86046b7c Mon Sep 17 00:00:00 2001 From: Daniel Spangenberger Date: Sat, 13 Jun 2026 12:45:19 -0400 Subject: [PATCH 4/4] sync spec: add AI Eval runs endpoints Adds the AI Eval runs API surface (tag "AI Eval"), which generates an omni ai-eval runs-* command set: - runs-list GET /api/v1/ai/eval/runs (--prompt-set-id required, --archived) - runs-create POST /api/v1/ai/eval/runs - runs-get GET /api/v1/ai/eval/runs/{runId} - runs-archive DELETE /api/v1/ai/eval/runs/{runId} - runs-cancel POST /api/v1/ai/eval/runs/{runId}/cancel - runs-unarchive POST /api/v1/ai/eval/runs/{runId}/unarchive The full re-sync from exploreomni/omni@main also reorders/reformats the embedded JSON; no other operations or params were added or removed. Co-Authored-By: Claude Fable 5 --- api/openapi.json | 16437 +++++++++++++++++++++------------------- cmd/omni/openapi.json | 16437 +++++++++++++++++++++------------------- 2 files changed, 17356 insertions(+), 15518 deletions(-) diff --git a/api/openapi.json b/api/openapi.json index 8697147..28c20c3 100644 --- a/api/openapi.json +++ b/api/openapi.json @@ -16015,9 +16015,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16120,9 +16117,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16265,9 +16259,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16344,9 +16335,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16425,9 +16413,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16543,9 +16528,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16618,9 +16600,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16710,9 +16689,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16742,9 +16718,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -16816,9 +16789,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -16938,9 +16908,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -16999,9 +16966,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -17056,9 +17020,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -17158,9 +17119,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -17202,7 +17160,7 @@ ] } ], - "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.)." + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.). Visibility is determined by placement in the filter-bar container." }, "map": { "type": "object", @@ -17277,7 +17235,7 @@ "additionalProperties": { "$ref": "#/components/schemas/QueryPresentationPatchExternal" }, - "description": "Query presentations keyed by tab ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete. Capped at 48 entries per patch." + "description": "Query presentations keyed by tab ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete. Capped at 48 entries per patch. When the request carries no `containers` and the document has a dashboard layout, dashboard-eligible tiles added at new keys are auto-placed on the dashboard's first page (non-renderable types such as CSV / dataset / query-view / dbt tabs are stored but not placed), and containers created by auto-placement are removed when their tile is deleted — containers placed via an explicit `containers` write are left in the layout. When `containers` is present it fully defines the layout; on a workbook-only document (no layout yet) tiles are stored without placement." }, "order": { "type": "array", @@ -20156,9 +20114,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20261,9 +20216,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20406,9 +20358,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20485,9 +20434,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20566,9 +20512,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20684,9 +20627,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20759,9 +20699,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20851,9 +20788,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20883,9 +20817,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -20957,9 +20888,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21079,9 +21007,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21140,9 +21065,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21197,9 +21119,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21299,9 +21218,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21343,7 +21259,7 @@ ] } ], - "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.)." + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.). Visibility is determined by placement in the filter-bar container." }, "map": { "type": "object", @@ -24194,7 +24110,7 @@ "$ref": "#/components/schemas/Containers" }, { - "description": "Container layout. When present, fully replaces the existing layout." + "description": "Container layout. When present, fully replaces the existing layout and disables automatic tile placement for the request." } ] }, @@ -24818,5573 +24734,6353 @@ "prompt_set" ] }, - "FoldersListResponse": { + "EvalRunsListResponse": { "type": "object", "properties": { - "pageInfo": { - "allOf": [ - { - "$ref": "#/components/schemas/PageInfo" - }, - { - "description": "Pagination information" - } - ] - }, - "records": { + "runs": { "type": "array", "items": { - "type": "object", - "properties": { - "_count": { - "type": "object", - "properties": { - "documents": { - "type": "number", - "description": "Number of documents in the folder" - }, - "favorites": { - "type": "number", - "description": "Number of users who have favorited this folder" - } - }, - "required": [ - "documents", - "favorites" - ], - "description": "Count statistics for the folder" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique folder identifier" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels associated with the folder" - }, - "name": { - "type": "string", - "description": "Name of the folder", - "example": "My Reports" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the folder owner" - }, - "path": { - "type": "string", - "description": "Full path to the folder", - "example": "/shared/reports/my-reports" - }, - "url": { - "type": "string", - "description": "URL to view the folder in the Omni UI.", - "example": "https://org.omni.co/f/my-reports" - } - }, - "required": [ - "id", - "name", - "ownerId", - "path", - "url" - ] + "$ref": "#/components/schemas/EvalRunListItem" }, - "description": "List of folders" + "description": "Runs for the prompt set, newest first, filtered to those whose model the caller can access." } }, "required": [ - "pageInfo", - "records" + "runs" ] }, - "FoldersCreateResponse": { + "EvalRunListItem": { "type": "object", "properties": { + "branch_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", + "example": null + }, + "branch_name": { + "type": [ + "string", + "null" + ], + "description": "Display name for the branch, if `branch_id` is set.", + "example": null + }, + "completed_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run reached a terminal state.", + "example": null + }, + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description for the run.", + "example": null + }, "id": { "type": "string", "format": "uuid", - "description": "ID of the created folder" + "description": "Unique identifier for the run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "name": { - "type": "string", - "description": "Name of the created folder" + "is_archived": { + "type": "boolean", + "description": "Whether the run has been archived.", + "example": false }, - "ownerId": { + "model_id": { "type": "string", "format": "uuid", - "description": "User ID of the folder owner" + "description": "The shared model this run was executed against.", + "example": "880e8400-e29b-41d4-a716-446655440003" }, - "path": { + "prompt_set_id": { "type": "string", - "description": "Full path to the folder" + "format": "uuid", + "description": "The prompt set this run was created from.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "scope": { + "run_number": { + "type": "integer", + "description": "Sequential, per-prompt-set run number.", + "example": 3 + }, + "stats": { + "$ref": "#/components/schemas/EvalRunStats" + }, + "status": { "type": "string", "enum": [ - "organization", - "restricted" + "RUNNING", + "COMPLETE", + "CANCELLED" ], - "description": "Share scope of the folder" + "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", + "example": "RUNNING" } }, "required": [ + "branch_id", + "branch_name", + "completed_at", + "created_at", + "description", "id", - "name", - "ownerId", - "path", - "scope" + "is_archived", + "model_id", + "prompt_set_id", + "run_number", + "stats", + "status" ] }, - "FoldersCreateBody": { + "EvalRunStats": { "type": "object", "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "Name of the folder to create", - "example": "My New Folder" - }, - "parentFolderId": { - "type": "string", - "format": "uuid", - "description": "Parent folder ID (omit to create at root level)" - }, - "scope": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Share scope for the folder" + "terminal": { + "type": "integer", + "description": "Number of per-prompt jobs that have reached a terminal state (COMPLETE, FAILED, or CANCELLED).", + "example": 8 }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID to create the folder as (for org-scoped API keys only)" + "total": { + "type": "integer", + "description": "Total number of per-prompt jobs in the run.", + "example": 12 } }, "required": [ - "name" + "terminal", + "total" ] }, - "FoldersDeleteResponse": { + "EvalRunsCreateResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the folder was deleted successfully" + "job_count": { + "type": "integer", + "description": "Number of per-prompt agentic jobs created for this run (one per prompt that fanned out successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects jobs created, not necessarily those successfully enqueued.", + "example": 12 + }, + "run": { + "$ref": "#/components/schemas/EvalRunDetail" } }, "required": [ - "success" + "job_count", + "run" ] }, - "FoldersUpdateResponse": { + "EvalRunDetail": { "type": "object", "properties": { - "id": { - "type": "string", + "branch_id": { + "type": [ + "string", + "null" + ], "format": "uuid", - "description": "Folder ID" + "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", + "example": null }, - "name": { - "type": "string", - "description": "Updated folder name" + "branch_name": { + "type": [ + "string", + "null" + ], + "description": "Display name for the branch, if `branch_id` is set.", + "example": null }, - "path": { - "type": "string", - "description": "Updated URL path segment for the folder (the folder's own segment only)" + "completed_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run reached a terminal state.", + "example": null + }, + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description for the run.", + "example": null + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the run has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this run was executed against.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set this run was created from.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalRunResult" + }, + "description": "Per-prompt results for this run, ordered by their creation order in the prompt set." + }, + "run_number": { + "type": "integer", + "description": "Sequential, per-prompt-set run number.", + "example": 3 + }, + "status": { + "type": "string", + "enum": [ + "RUNNING", + "COMPLETE", + "CANCELLED" + ], + "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", + "example": "RUNNING" } }, "required": [ + "branch_id", + "branch_name", + "completed_at", + "created_at", + "description", "id", - "name", - "path" - ] + "is_archived", + "model_id", + "prompt_set_id", + "results", + "run_number", + "status" + ], + "description": "The newly created run with its initial results." }, - "FoldersUpdateBody": { + "EvalRunResult": { "type": "object", "properties": { - "name": { + "agentic_job": { + "$ref": "#/components/schemas/EvalRunResultAgenticJob" + }, + "cost": { + "type": [ + "number", + "null" + ], + "description": "Total LLM cost (USD) for this prompt, if available.", + "example": 0.0021 + }, + "error_reason": { + "type": [ + "string", + "null" + ], + "description": "Failure reason string for prompts whose underlying job failed.", + "example": null + }, + "expectation": { + "type": [ + "string", + "null" + ], + "description": "The prompt's expectation as of run creation (snapshotted, so later prompt edits don't change past runs), or null when none was set. The analysis judge scores the analysis against it.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { "type": "string", - "minLength": 1, - "description": "New display name for the folder", - "example": "Q1 Reports" + "format": "uuid", + "description": "Unique identifier for the run result row.", + "example": "aa0e8400-e29b-41d4-a716-446655440005" }, - "path": { + "prompt": { "type": "string", - "minLength": 1, - "pattern": "^[a-zA-Z0-9-]+$", - "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", - "example": "q1-reports" + "description": "The prompt text that was evaluated.", + "example": "What are the top 5 products by revenue?" }, - "resolvePathConflict": { - "type": "boolean", - "default": false, - "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." + "score": { + "type": [ + "number", + "null" + ], + "description": "Numeric judge score for this prompt result, if scoring ran.", + "example": 0.9 + }, + "scoring_cost": { + "type": [ + "number", + "null" + ], + "description": "Total LLM cost (USD) for scoring this prompt result.", + "example": 0.0004 + }, + "timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Wall-clock duration of the underlying job in milliseconds.", + "example": 4321 } - } + }, + "required": [ + "agentic_job", + "cost", + "error_reason", + "expectation", + "id", + "prompt", + "score", + "scoring_cost", + "timing_ms" + ] }, - "FoldersGetPermissionsResponse": { + "EvalRunResultAgenticJob": { "type": "object", "properties": { - "permits": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "description": "Whether access boost is enabled for this permit" - }, - "role": { - "type": "string", - "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", - "example": "VIEWER" - }, - "userGroupId": { - "type": "string", - "description": "User group ID if this is a group permit" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID if this is a user permit" - } - }, - "required": [ - "role" - ] - }, - "description": "List of permission permits for the folder" + "conversation_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Conversation the agentic job belongs to.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Agentic job identifier.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "state": { + "type": "string", + "enum": [ + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" + ], + "description": "Current state of the agentic job that ran this prompt.", + "example": "COMPLETE" } }, "required": [ - "permits" + "conversation_id", + "id", + "state" ] }, - "FoldersAddPermissionsResponse": { + "EvalApiError429": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were added successfully" + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Too many active runs; wait for an in-flight run to finish" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 429 } }, "required": [ - "success" + "detail", + "status" ] }, - "FoldersAddPermissionsBody": { + "EvalApiError503": { "type": "object", "properties": { - "accessBoost": { - "type": "boolean", - "default": false, - "description": "Whether to grant access boost" - }, - "role": { + "detail": { "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" + "description": "Human-readable error message describing what went wrong.", + "example": "AI eval is paused for this organization" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 503 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalRunsCreateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" ], - "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", - "example": "VIEWER" + "maxLength": 1024, + "description": "Optional human-readable description for the run. Pass `null` to clear (or omit). Max 1024 characters.", + "example": "Re-running after switching to gpt-4o for query generation" }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to grant permission to" + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set to execute.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" + "run_config": { + "type": "object", + "properties": { + "branch_id": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID to run against. Must be a branch of the prompt set's model.", + "example": "440e8400-e29b-41d4-a716-446655440006" + } }, - "default": [], - "description": "User IDs to grant permission to" + "description": "Per-run configuration. Optional — omit if no overrides." } }, "required": [ - "role" - ], - "additionalProperties": false + "prompt_set_id" + ] }, - "FoldersUpdatePermissionsResponse": { + "EvalRunsGetResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were updated successfully" + "run": { + "$ref": "#/components/schemas/EvalRunDetail" } }, "required": [ - "success" + "run" ] }, - "FoldersUpdatePermissionsBody": { + "EvalRunsDeleteResponse": { "type": "object", "properties": { - "accessBoost": { + "is_archived": { "type": "boolean", - "description": "Whether to grant access boost" - }, - "role": { - "type": "string", "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" + true ], - "description": "New content role to assign" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to update permissions for" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to update permissions for" + "description": "Always `true` on success — the run has been archived." } }, - "additionalProperties": false + "required": [ + "is_archived" + ] }, - "FoldersRevokePermissionsResponse": { + "EvalRunsCancelResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were revoked successfully" + "cancelled": { + "type": "integer", + "description": "Number of per-prompt agentic jobs that were cancelled by this request.", + "example": 4 + }, + "run": { + "allOf": [ + { + "$ref": "#/components/schemas/EvalRunDetail" + }, + { + "description": "The cancelled run. `status: CANCELLED` and `is_archived: true` after this call." + } + ] + }, + "total": { + "type": "integer", + "description": "Total number of per-prompt jobs in the run.", + "example": 12 } }, "required": [ - "success" + "cancelled", + "run", + "total" ] }, - "FoldersRevokePermissionsBody": { + "EvalRunsUnarchiveResponse": { "type": "object", "properties": { - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to revoke permissions from" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to revoke permissions from" + "is_archived": { + "type": "boolean", + "enum": [ + false + ], + "description": "Always `false` on success — the run has been unarchived." } }, - "additionalProperties": false + "required": [ + "is_archived" + ] }, - "LabelsListResponse": { + "FoldersListResponse": { "type": "object", "properties": { - "labels": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { "type": "array", "items": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents in the folder" + }, + "favorites": { + "type": "number", + "description": "Number of users who have favorited this folder" + } + }, + "required": [ + "documents", + "favorites" ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" + "description": "Count statistics for the folder" }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" + "id": { + "type": "string", + "format": "uuid", + "description": "Unique folder identifier" }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels associated with the folder" }, "name": { "type": "string", - "description": "Label name", - "example": "verified" + "description": "Name of the folder", + "example": "My Reports" }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "/shared/reports/my-reports" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/my-reports" } }, "required": [ - "color", - "description", - "homepage", + "id", "name", - "usage_count", - "verified" + "ownerId", + "path", + "url" ] }, - "description": "List of labels" + "description": "List of folders" } }, "required": [ - "labels" + "pageInfo", + "records" ] }, - "LabelsCreateResponse": { + "FoldersCreateResponse": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the created folder" }, "name": { "type": "string", - "description": "Label name", - "example": "verified" + "description": "Name of the created folder" }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" + "path": { + "type": "string", + "description": "Full path to the folder" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope of the folder" } }, "required": [ - "color", - "description", - "homepage", + "id", "name", - "usage_count", - "verified" + "ownerId", + "path", + "scope" ] }, - "LabelsCreateBody": { + "FoldersCreateBody": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "default": null, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" + "name": { + "type": "string", + "minLength": 1, + "description": "Name of the folder to create", + "example": "My New Folder" }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "default": null, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "default": false, - "description": "Show label on homepage. Requires admin permissions." + "parentFolderId": { + "type": "string", + "format": "uuid", + "description": "Parent folder ID (omit to create at root level)" }, - "name": { + "scope": { "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope for the folder" }, - "verified": { - "type": "boolean", - "default": false, - "description": "Mark as verified label. Requires admin permissions." + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to create the folder as (for org-scoped API keys only)" } }, "required": [ "name" ] }, - "LabelsGetResponse": { + "FoldersDeleteResponse": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { + "success": { "type": "boolean", - "description": "Whether label is verified" + "description": "Whether the folder was deleted successfully" } }, "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" + "success" ] }, - "LabelsUpdateResponse": { + "FoldersUpdateResponse": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + "id": { + "type": "string", + "format": "uuid", + "description": "Folder ID" }, "name": { "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + "description": "Updated folder name" }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" + "path": { + "type": "string", + "description": "Updated URL path segment for the folder (the folder's own segment only)" } }, "required": [ - "color", - "description", - "homepage", + "id", "name", - "usage_count", - "verified" + "path" ] }, - "LabelsUpdateBody": { + "FoldersUpdateBody": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Show label on homepage. Requires admin permissions to modify." - }, "name": { "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" + "minLength": 1, + "description": "New display name for the folder", + "example": "Q1 Reports" }, - "verified": { + "path": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z0-9-]+$", + "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", + "example": "q1-reports" + }, + "resolvePathConflict": { "type": "boolean", - "description": "Mark as verified label. Requires admin permissions to modify." + "default": false, + "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." } } }, - "ModelsListResponse": { + "FoldersGetPermissionsResponse": { "type": "object", "properties": { - "pageInfo": { - "allOf": [ - { - "$ref": "#/components/schemas/PageInfo" - }, - { - "description": "Pagination information" - } - ] - }, - "records": { + "permits": { "type": "array", "items": { "type": "object", "properties": { - "baseModelId": { - "type": [ - "string", - "null" - ], - "description": "Base model ID for branch/extension models" - }, - "branches": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Branch ID" - }, - "name": { - "type": "string", - "description": "Branch name" - } - }, - "required": [ - "id", - "name" - ] - }, - "description": "Active branches (if include=activeBranches)" - }, - "connectionId": { - "type": [ - "string", - "null" - ], - "description": "Connection ID" + "accessBoost": { + "type": "boolean", + "description": "Whether access boost is enabled for this permit" }, - "createdAt": { + "role": { "type": "string", - "description": "Creation timestamp" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Deletion timestamp" + "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", + "example": "VIEWER" }, - "id": { + "userGroupId": { "type": "string", - "description": "Model ID" - }, - "modelKind": { - "type": [ - "string", - "null" - ], - "description": "Model kind" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Model name" + "description": "User group ID if this is a group permit" }, - "updatedAt": { + "userId": { "type": "string", - "description": "Last update timestamp" + "format": "uuid", + "description": "User ID if this is a user permit" } }, "required": [ - "baseModelId", - "connectionId", - "createdAt", - "deletedAt", - "id", - "modelKind", - "name", - "updatedAt" + "role" ] }, - "description": "List of model records" + "description": "List of permission permits for the folder" } }, "required": [ - "pageInfo", - "records" + "permits" ] }, - "CreateModelSchemaBase": { + "FoldersAddPermissionsResponse": { "type": "object", "properties": { - "accessGrants": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoostable": { - "type": "boolean" - }, - "allowedValues": { - "type": "array", - "items": { - "type": "string" - } - }, - "codeComments": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "ignored": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "userAttribute": { - "type": "string" - } - }, - "required": [ - "accessBoostable", - "name" - ] - }, - "description": "Access grants for the model" - }, - "allowAsWorkbookBase": { + "success": { "type": "boolean", - "description": "Allow this model as a workbook base" - }, - "baseModelId": { - "type": "string", - "description": "Base model ID for extension or branch models" + "description": "Whether the permissions were added successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersAddPermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "default": false, + "description": "Whether to grant access boost" }, - "connectionId": { + "role": { "type": "string", - "description": "Connection ID for the model" - }, - "modelKind": { - "anyOf": [ - { - "type": "string", - "enum": [ - "SCHEMA" - ] - }, - { - "type": "string", - "enum": [ - "SHARED" - ] - }, - { - "type": "string", - "enum": [ - "SHARED_EXTENSION" - ] - }, - { - "type": "string", - "enum": [ - "BRANCH" - ] - } + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" ], - "default": "SCHEMA", - "description": "Kind of model to create" + "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", + "example": "VIEWER" }, - "modelName": { - "type": "string", - "description": "Name for the model" + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to grant permission to" }, - "usesIsolatedBranches": { - "type": "boolean", - "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to grant permission to" } }, "required": [ - "connectionId" - ] + "role" + ], + "additionalProperties": false }, - "ModelsUpdateResponse": { + "FoldersUpdatePermissionsResponse": { "type": "object", "properties": { - "model": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Model ID" - }, - "name": { - "type": "string", - "description": "Updated model name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Updated model details" - }, "success": { "type": "boolean", - "description": "Whether the operation succeeded" + "description": "Whether the permissions were updated successfully" } }, "required": [ - "model", "success" ] }, - "ModelsUpdateBody": { + "FoldersUpdatePermissionsBody": { "type": "object", "properties": { - "name": { + "accessBoost": { + "type": "boolean", + "description": "Whether to grant access boost" + }, + "role": { "type": "string", - "minLength": 1, - "description": "New name for the model", - "example": "My Renamed Model" + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "New content role to assign" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to update permissions for" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to update permissions for" } }, - "required": [ - "name" - ] + "additionalProperties": false }, - "JobsGetStatusResponse": { + "FoldersRevokePermissionsResponse": { "type": "object", "properties": { - "job_id": { - "type": "string", - "description": "The job ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "job_type": { - "type": "string", - "description": "The type of job (e.g., REFRESH_SCHEMA)", - "example": "REFRESH_SCHEMA" - }, - "status": { - "type": "string", - "enum": [ - "IN_PROGRESS", - "COMPLETED", - "FAILED" - ], - "description": "Current status of the job", - "example": "COMPLETED" + "success": { + "type": "boolean", + "description": "Whether the permissions were revoked successfully" } }, "required": [ - "job_id", - "job_type", - "status" + "success" ] }, - "ModelsGetSchemasResponse": { + "FoldersRevokePermissionsBody": { "type": "object", "properties": { - "schemas": { + "userGroupIds": { "type": "array", "items": { "type": "string" }, - "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" + "default": [], + "description": "User group IDs to revoke permissions from" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to revoke permissions from" } }, - "required": [ - "schemas" - ] + "additionalProperties": false }, - "ModelsGetViewResponse": { + "LabelsListResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "views": { + "labels": { "type": "array", "items": { "type": "object", "properties": { - "description": { - "type": "string", - "description": "View description" - }, - "fields": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Field name" - }, - "type": { - "type": "string", - "enum": [ - "dimension", - "measure", - "filter" - ], - "description": "Field type" - } - }, - "required": [ - "name", - "type" - ] - }, - "description": "Fields in the view" + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, - "hidden": { - "type": "boolean", - "description": "Whether the view is hidden" + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "label": { - "type": "string", - "description": "View label" + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" }, "name": { "type": "string", - "description": "View name" + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" } }, "required": [ - "fields", - "name" + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" ] }, - "description": "List of views" + "description": "List of labels" } }, "required": [ - "success", - "views" + "labels" ] }, - "ModelsUpdateViewBody": { + "LabelsCreateResponse": { "type": "object", "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the view" + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, "description": { - "type": "string", - "description": "View description" - }, - "format": { - "type": "string", - "description": "View format" + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "hidden": { + "homepage": { "type": "boolean", - "description": "Whether the view is hidden" + "description": "Whether label is shown on homepage" }, - "label": { + "name": { "type": "string", - "description": "View label" + "description": "Label name", + "example": "verified" }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the view" + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" } - } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] }, - "ModelsUpdateFieldBody": { + "LabelsCreateBody": { "type": "object", "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "allValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Deprecated: use sampleValues instead" - }, - "binBoundaries": { - "type": "array", - "items": { - "type": "number" - }, - "description": "Bin boundaries for binned fields" - }, - "binLabels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels for bins" + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "default": null, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, "description": { - "type": "string", - "description": "Field description" + "type": [ + "string", + "null" + ], + "maxLength": 500, + "default": null, + "description": "Label description", + "example": "Important items that need attention" }, - "drillFields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Drill-down fields" + "homepage": { + "type": "boolean", + "default": false, + "description": "Show label on homepage. Requires admin permissions." }, - "elseValue": { + "name": { "type": "string", - "description": "Else value for grouped fields" + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" }, - "filters": { - "type": "object", - "additionalProperties": {}, - "description": "Filters for the field" + "verified": { + "type": "boolean", + "default": false, + "description": "Mark as verified label. Requires admin permissions." + } + }, + "required": [ + "name" + ] + }, + "LabelsGetResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, - "format": { - "type": "string", - "description": "Field format" + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "groupFilters": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Group filters" + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" }, - "groupLabel": { + "name": { "type": "string", - "description": "Group label" + "description": "Label name", + "example": "verified" }, - "groupNames": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Group names" + "usage_count": { + "type": "number", + "description": "Number of documents with this label" }, - "hidden": { + "verified": { "type": "boolean", - "description": "Whether the field is hidden" + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, - "ignored": { - "type": "boolean", - "description": "Whether the field is ignored" + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "isCalc": { + "homepage": { "type": "boolean", - "description": "Whether this is a calculation field" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "newFieldName": { - "type": "string", - "description": "New field name (for rename)" + "description": "Whether label is shown on homepage" }, - "newViewName": { + "name": { "type": "string", - "description": "New view name (for move)" + "description": "Label name", + "example": "verified" }, - "sampleValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Sample values for the field" + "usage_count": { + "type": "number", + "description": "Number of documents with this label" }, - "sql": { - "type": "string", - "description": "SQL expression for the field" + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, - "synonyms": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Synonyms for the field" + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" + "homepage": { + "type": "boolean", + "description": "Show label on homepage. Requires admin permissions to modify." }, - "topicContext": { + "name": { "type": "string", - "description": "Topic context for the field" + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "description": "Mark as verified label. Requires admin permissions to modify." } } }, - "ModelsListTopicsResponse": { + "ModelsListResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] }, - "topics": { + "records": { "type": "array", "items": { "type": "object", "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" + "baseModelId": { + "type": [ + "string", + "null" + ], + "description": "Base model ID for branch/extension models" }, - "description": { - "type": "string", - "description": "Topic description" + "branches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Branch ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ] + }, + "description": "Active branches (if include=activeBranches)" }, - "group_label": { + "connectionId": { + "type": [ + "string", + "null" + ], + "description": "Connection ID" + }, + "createdAt": { "type": "string", - "description": "Group label" + "description": "Creation timestamp" }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Deletion timestamp" }, - "label": { + "id": { "type": "string", - "description": "Topic label" + "description": "Model ID" + }, + "modelKind": { + "type": [ + "string", + "null" + ], + "description": "Model kind" }, "name": { + "type": [ + "string", + "null" + ], + "description": "Model name" + }, + "updatedAt": { "type": "string", - "description": "Topic name" + "description": "Last update timestamp" } }, "required": [ - "base_view_name", - "name" + "baseModelId", + "connectionId", + "createdAt", + "deletedAt", + "id", + "modelKind", + "name", + "updatedAt" ] }, - "description": "List of topics" + "description": "List of model records" } }, "required": [ - "success", - "topics" + "pageInfo", + "records" ] }, - "ModelsGetTopicResponse": { + "CreateModelSchemaBase": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "topic": { - "type": "object", - "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" - }, - "description": { - "type": "string", - "description": "Topic description" - }, - "group_label": { - "type": "string", - "description": "Group label" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "name": { - "type": "string", - "description": "Topic name" - }, - "relationships": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} + "accessGrants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoostable": { + "type": "boolean" }, - "description": "Relationships for the topic" - }, - "views": { - "type": "array", - "items": { + "allowedValues": { + "type": "array", + "items": { + "type": "string" + } + }, + "codeComments": { "type": "object", - "additionalProperties": {} + "additionalProperties": { + "type": "string" + } }, - "description": "Views available in the topic" - } + "ignored": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "userAttribute": { + "type": "string" + } + }, + "required": [ + "accessBoostable", + "name" + ] }, - "required": [ - "base_view_name", - "name", - "relationships", - "views" - ], - "description": "Topic details with relationships and views" - } - }, - "required": [ - "success", - "topic" - ] - }, - "ModelsUpdateTopicBody": { - "type": "object", - "properties": { - "description": { + "description": "Access grants for the model" + }, + "allowAsWorkbookBase": { + "type": "boolean", + "description": "Allow this model as a workbook base" + }, + "baseModelId": { "type": "string", - "description": "Topic description" + "description": "Base model ID for extension or branch models" }, - "groupLabel": { + "connectionId": { "type": "string", - "description": "Group label for the topic" + "description": "Connection ID for the model" }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" + "modelKind": { + "anyOf": [ + { + "type": "string", + "enum": [ + "SCHEMA" + ] + }, + { + "type": "string", + "enum": [ + "SHARED" + ] + }, + { + "type": "string", + "enum": [ + "SHARED_EXTENSION" + ] + }, + { + "type": "string", + "enum": [ + "BRANCH" + ] + } + ], + "default": "SCHEMA", + "description": "Kind of model to create" }, - "label": { + "modelName": { "type": "string", - "description": "Topic label" + "description": "Name for the model" }, - "newTopicName": { - "type": "string", - "description": "New topic name (for rename)" + "usesIsolatedBranches": { + "type": "boolean", + "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" } - } + }, + "required": [ + "connectionId" + ] }, - "ModelsCreateFieldBody": { + "ModelsUpdateResponse": { "type": "object", "properties": { - "aggregateType": { - "type": "string", - "enum": [ - "AVERAGE", - "COUNT", - "COUNT_DISTINCT", - "LIST", - "MAX", - "MIN", - "SUM", - "MEDIAN", - "PERCENTILE", - "AVERAGE_DISTINCT_ON", - "SUM_DISTINCT_ON", - "MEDIAN_DISTINCT_ON", - "PERCENTILE_DISTINCT_ON", - "SEMANTIC_VIEW_AGG" + "model": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Model ID" + }, + "name": { + "type": "string", + "description": "Updated model name" + } + }, + "required": [ + "id", + "name" ], - "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", - "example": "SUM" - }, - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "description": { - "type": "string", - "description": "Field description" - }, - "fieldName": { - "type": "string", - "description": "Field name", - "example": "total_revenue" - }, - "format": { - "type": "string", - "description": "Field format" + "description": "Updated model details" }, - "hidden": { + "success": { "type": "boolean", - "description": "Whether the field is hidden" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "sql": { - "type": "string", - "description": "SQL expression for the field" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" - }, - "topicContext": { - "type": "string", - "description": "Topic context for topic-scoped fields" - }, - "viewName": { + "description": "Whether the operation succeeded" + } + }, + "required": [ + "model", + "success" + ] + }, + "ModelsUpdateBody": { + "type": "object", + "properties": { + "name": { "type": "string", - "description": "View to add the field to", - "example": "orders" + "minLength": 1, + "description": "New name for the model", + "example": "My Renamed Model" } }, "required": [ - "fieldName", - "viewName" - ], - "additionalProperties": false + "name" + ] }, - "ModelsRefreshResponse": { + "JobsGetStatusResponse": { "type": "object", "properties": { - "jobId": { + "job_id": { "type": "string", - "description": "Job ID for the refresh operation" + "description": "The job ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "modelId": { + "job_type": { "type": "string", - "description": "Model ID being refreshed" + "description": "The type of job (e.g., REFRESH_SCHEMA)", + "example": "REFRESH_SCHEMA" }, "status": { "type": "string", "enum": [ - "running", - "completed", - "failed" + "IN_PROGRESS", + "COMPLETED", + "FAILED" ], - "description": "Current status of the refresh" + "description": "Current status of the job", + "example": "COMPLETED" } }, "required": [ - "jobId", - "modelId", + "job_id", + "job_type", "status" ] }, - "ModelsValidateResponse": { + "ModelsGetSchemasResponse": { "type": "object", "properties": { - "issues": { + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" + } + }, + "required": [ + "schemas" + ] + }, + "ModelsGetViewResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "views": { "type": "array", "items": { "type": "object", "properties": { - "field": { + "description": { "type": "string", - "description": "Field name with the issue" + "description": "View description" }, - "message": { - "type": "string", - "description": "Validation issue message" + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Field name" + }, + "type": { + "type": "string", + "enum": [ + "dimension", + "measure", + "filter" + ], + "description": "Field type" + } + }, + "required": [ + "name", + "type" + ] + }, + "description": "Fields in the view" }, - "severity": { + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { "type": "string", - "enum": [ - "error", - "warning" - ], - "description": "Issue severity" + "description": "View label" }, - "view": { + "name": { "type": "string", - "description": "View name with the issue" + "description": "View name" } }, "required": [ - "message", - "severity" + "fields", + "name" ] }, - "description": "List of validation issues" - }, - "valid": { - "type": "boolean", - "description": "Whether the model is valid" + "description": "List of views" } }, "required": [ - "issues", - "valid" + "success", + "views" ] }, - "ModelsMigrateBody": { + "ModelsUpdateViewBody": { "type": "object", "properties": { - "branchName": { + "aiContext": { "type": "string", - "description": "Branch name for the target model" + "description": "AI context for the view" }, - "commitMessage": { + "description": { "type": "string", - "description": "Commit message for git sync" - }, - "deleteViewsAndTopicsMissingFromSource": { - "type": "boolean", - "default": true, - "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead — useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." + "description": "View description" }, - "gitRef": { + "format": { "type": "string", - "description": "Git reference" + "description": "View format" }, - "targetModelId": { + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { "type": "string", - "format": "uuid", - "description": "Target model ID to migrate to" - } - }, - "required": [ - "targetModelId" - ] - }, - "ModelsDbtExposuresResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + "description": "View label" }, - "records": { + "tags": { "type": "array", "items": { - "$ref": "#/components/schemas/DbtExposureWithMeta" - } + "type": "string" + }, + "description": "Tags for the view" } - }, - "required": [ - "pageInfo", - "records" - ] + } }, - "DbtExposureWithMeta": { + "ModelsUpdateFieldBody": { "type": "object", "properties": { - "dashboard_identifier": { + "aiContext": { "type": "string", - "description": "Identifier of the dashboard that generated this exposure" + "description": "AI context for the field" }, - "deduplication_name": { - "type": "string", - "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." + "allValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Deprecated: use sampleValues instead" }, - "exposure": { - "$ref": "#/components/schemas/DbtExposure" - } - }, - "required": [ - "dashboard_identifier", - "deduplication_name", - "exposure" - ] - }, - "DbtExposure": { - "type": "object", - "properties": { - "depends_on": { + "binBoundaries": { + "type": "array", + "items": { + "type": "number" + }, + "description": "Bin boundaries for binned fields" + }, + "binLabels": { "type": "array", "items": { "type": "string" }, - "description": "List of dbt model references (e.g. ref('model_name'))", - "example": [ - "ref('orders')", - "ref('customers')" - ] + "description": "Labels for bins" }, - "label": { + "description": { "type": "string", - "description": "Original dashboard name" + "description": "Field description" }, - "name": { + "drillFields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Drill-down fields" + }, + "elseValue": { "type": "string", - "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", - "example": "my_dashboard" + "description": "Else value for grouped fields" }, - "owner": { - "$ref": "#/components/schemas/DbtExposureOwner" + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filters for the field" }, - "type": { + "format": { "type": "string", - "enum": [ - "dashboard", - "notebook", - "analysis", - "ml", - "application" - ], - "description": "Type of the exposure", - "example": "dashboard" + "description": "Field format" }, - "url": { - "type": "string", - "description": "URL of the dashboard" - } - }, - "required": [ - "depends_on", - "name", - "owner", - "type" - ], - "description": "The dbt exposure for this dashboard." - }, - "DbtExposureOwner": { - "type": "object", - "properties": { - "email": { - "type": "string", - "description": "Email of the dashboard owner" + "groupFilters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Group filters" }, - "name": { - "type": "string", - "description": "Name of the dashboard owner" - } - }, - "required": [ - "email", - "name" - ] - }, - "ModelsBranchDbtBody": { - "type": "object", - "properties": { - "dbt_environment_id": { + "groupLabel": { "type": "string", - "format": "uuid", - "description": "ID of the dbt environment to activate on this branch", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Group label" }, - "dbt_git_branch": { - "type": "string", - "description": "Git branch to associate with the dbt environment", - "example": "feature/new-metrics" - } - }, - "required": [ - "dbt_environment_id" - ] - }, - "ModelsMergeBranchResponse": { - "type": "object", - "properties": { - "failed_drafts_count": { - "type": "number", - "description": "Number of drafts that failed to publish" + "groupNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Group names" }, - "git_synced": { + "hidden": { "type": "boolean", - "description": "Whether git was synced" + "description": "Whether the field is hidden" }, - "published_drafts_count": { - "type": "number", - "description": "Number of drafts published" + "ignored": { + "type": "boolean", + "description": "Whether the field is ignored" }, - "success": { + "isCalc": { "type": "boolean", - "description": "Whether the merge succeeded" - } - }, - "required": [ - "failed_drafts_count", - "git_synced", - "published_drafts_count", - "success" - ] - }, - "ModelsMergeBranchBody": { - "type": "object", - "properties": { - "commit_message": { + "description": "Whether this is a calculation field" + }, + "label": { "type": "string", - "description": "Custom commit message for git sync" + "description": "Field label" }, - "delete_branch": { - "type": "boolean", - "default": false, - "description": "Delete the branch after merging" + "newFieldName": { + "type": "string", + "description": "New field name (for rename)" }, - "force_override_git_settings": { - "type": "boolean", - "default": false, - "description": "Override PR-required or git-follower settings" + "newViewName": { + "type": "string", + "description": "New view name (for move)" }, - "publish_drafts": { - "type": "boolean", - "default": true, - "description": "Publish branch-attached drafts" - } - } - }, - "ModelsCommitResponse": { - "type": "object", - "properties": { - "did_sync": { - "type": "boolean", - "description": "Whether a sync operation was performed against git" + "sampleValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sample values for the field" }, - "git_sha": { - "type": [ - "string", - "null" - ], - "description": "The git SHA of the commit that was pushed (null if no commit was needed)" + "sql": { + "type": "string", + "description": "SQL expression for the field" }, - "in_sync": { - "type": "boolean", - "description": "Whether the branch is in sync with git after the operation" + "synonyms": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Synonyms for the field" }, - "pr_url": { - "type": [ - "string", - "null" - ], - "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for the field" } - }, - "required": [ - "did_sync", - "git_sha", - "in_sync", - "pr_url" - ] + } }, - "ModelsCommitBody": { + "ModelsListTopicsResponse": { "type": "object", "properties": { - "allow_branch_exists": { + "success": { "type": "boolean", - "default": true, - "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", - "example": true - }, - "branch_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to commit.", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "commit_message": { - "type": "string", - "minLength": 1, - "description": "Commit message for the git commit.", - "example": "Add new orders view" + "description": "Whether the operation succeeded" }, - "require_branch_exists": { - "type": "boolean", - "default": false, - "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", - "example": false + "topics": { + "type": "array", + "items": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + } + }, + "required": [ + "base_view_name", + "name" + ] + }, + "description": "List of topics" } }, "required": [ - "branch_id", - "commit_message" + "success", + "topics" ] }, - "ModelsCacheResetResponse": { + "ModelsGetTopicResponse": { "type": "object", "properties": { - "cache_reset": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topic": { "type": "object", "properties": { - "created_at": { - "type": [ - "string", - "null" - ], - "description": "Creation timestamp" + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" }, - "model_id": { + "description": { "type": "string", - "description": "Model ID" + "description": "Topic description" }, - "policy_name": { + "group_label": { "type": "string", - "description": "Cache policy name" + "description": "Group label" }, - "reset_at": { - "type": [ - "string", - "null" - ], - "description": "Reset timestamp" + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" }, - "updated_at": { - "type": [ - "string", - "null" - ], - "description": "Last update timestamp" + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + }, + "relationships": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Relationships for the topic" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Views available in the topic" } }, "required": [ - "created_at", - "model_id", - "policy_name", - "reset_at", - "updated_at" + "base_view_name", + "name", + "relationships", + "views" ], - "description": "Cache reset details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" + "description": "Topic details with relationships and views" } }, "required": [ - "cache_reset", - "success" + "success", + "topic" ] }, - "ModelsCacheResetBody": { + "ModelsUpdateTopicBody": { "type": "object", "properties": { - "resetAt": { + "description": { "type": "string", - "description": "ISO-8601 timestamp for when to reset the cache", - "example": "2024-01-15T12:00:00Z" + "description": "Topic description" + }, + "groupLabel": { + "type": "string", + "description": "Group label for the topic" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "newTopicName": { + "type": "string", + "description": "New topic name (for rename)" } } }, - "ModelsGitGetResponse": { + "ModelsCreateFieldBody": { "type": "object", "properties": { - "authMethod": { + "aggregateType": { "type": "string", "enum": [ - "ssh", - "https_token" + "AVERAGE", + "COUNT", + "COUNT_DISTINCT", + "LIST", + "MAX", + "MIN", + "SUM", + "MEDIAN", + "PERCENTILE", + "AVERAGE_DISTINCT_ON", + "SUM_DISTINCT_ON", + "MEDIAN_DISTINCT_ON", + "PERCENTILE_DISTINCT_ON", + "SEMANTIC_VIEW_AGG" ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" + "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", + "example": "SUM" }, - "baseBranch": { + "aiContext": { "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false + "description": "AI context for the field" }, - "cloneUrl": { + "description": { "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false + "description": "Field description" }, - "gitServiceProvider": { + "fieldName": { "type": "string", - "description": "The git provider type", - "example": "github" + "description": "Field name", + "example": "total_revenue" }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" + "format": { + "type": "string", + "description": "Field format" }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" }, - "requirePullRequest": { + "label": { "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" + "description": "Field label" }, - "sshUrl": { + "sql": { "type": "string", - "deprecated": true, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository." + "description": "SQL expression for the field" }, - "webUrl": { - "type": [ - "string", - "null" - ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" }, - "webhookSecret": { + "topicContext": { "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + "description": "Topic context for topic-scoped fields" }, - "webhookUrl": { + "viewName": { "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." + "description": "View to add the field to", + "example": "orders" } }, "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" - ] + "fieldName", + "viewName" + ], + "additionalProperties": false }, - "ModelsGitCreateResponse": { + "ModelsRefreshResponse": { "type": "object", "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false - }, - "cloneUrl": { + "jobId": { "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false + "description": "Job ID for the refresh operation" }, - "gitServiceProvider": { + "modelId": { "type": "string", - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" - }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." + "description": "Model ID being refreshed" }, - "requirePullRequest": { + "status": { "type": "string", "enum": [ - "always", - "users-only", - "never" - ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" - }, - "sshUrl": { - "type": "string", - "deprecated": true, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository." - }, - "webUrl": { - "type": [ - "string", - "null" + "running", + "completed", + "failed" ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" - }, - "webhookSecret": { - "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" - }, - "webhookUrl": { - "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." + "description": "Current status of the refresh" } }, "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" + "jobId", + "modelId", + "status" ] }, - "ModelsGitCreateBody": { + "ModelsValidateResponse": { "type": "object", "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "default": "ssh", - "description": "Authentication method. \"ssh\" for deploy key (default), \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "default": "main", - "description": "The target branch for Omni pull requests. Defaults to \"main\"", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "default": false, - "description": "If true, all pull requests will create a branch in Omni. Defaults to false", - "example": false - }, - "cloneUrl": { - "type": "string", - "minLength": 1, - "description": "Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth.", - "example": "git@github.com:org/repo.git" + "issues": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field name with the issue" + }, + "message": { + "type": "string", + "description": "Validation issue message" + }, + "severity": { + "type": "string", + "enum": [ + "error", + "warning" + ], + "description": "Issue severity" + }, + "view": { + "type": "string", + "description": "View name with the issue" + } + }, + "required": [ + "message", + "severity" + ] + }, + "description": "List of validation issues" }, - "gitFollower": { + "valid": { "type": "boolean", - "default": false, - "description": "If true, the shared model will be read-only. Defaults to false", - "example": false - }, - "gitServiceProvider": { + "description": "Whether the model is valid" + } + }, + "required": [ + "issues", + "valid" + ] + }, + "ModelsMigrateBody": { + "type": "object", + "properties": { + "branchName": { "type": "string", - "enum": [ - "github", - "gitlab", - "azure_devops", - "bitbucket", - "bitbucket_datacenter", - "auto" - ], - "default": "auto", - "description": "The git provider type. Use \"auto\" for automatic detection. Defaults to \"auto\"", - "example": "auto" + "description": "Branch name for the target model" }, - "modelPath": { + "commitMessage": { "type": "string", - "description": "Path to model files in the repository. Defaults to omni/. Use a plain name (e.g., \"my_model\") for omni/my_model, or a leading slash for a custom path (e.g., \"/bi/models/sales\")", - "example": "my_model" + "description": "Commit message for git sync" }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "default": "never", - "description": "Controls when pull requests are required. Defaults to \"never\"", - "example": "never" + "deleteViewsAndTopicsMissingFromSource": { + "type": "boolean", + "default": true, + "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead — useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." }, - "sshUrl": { + "gitRef": { "type": "string", - "minLength": 1, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", - "example": "git@github.com:org/repo.git", - "deprecated": true + "description": "Git reference" }, - "token": { + "targetModelId": { "type": "string", - "maxLength": 1000, - "pattern": "^[a-zA-Z0-9_\\-.]+$", - "description": "HTTPS token for authentication (deploy token value, PAT, etc.). Required when authMethod is \"https_token\"." + "format": "uuid", + "description": "Target model ID to migrate to" + } + }, + "required": [ + "targetModelId" + ] + }, + "ModelsDbtExposuresResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" }, - "webUrl": { - "type": "string", - "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", - "example": "https://github.com/org/repo" + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtExposureWithMeta" + } } - } + }, + "required": [ + "pageInfo", + "records" + ] }, - "ModelsGitUpdateResponse": { + "DbtExposureWithMeta": { "type": "object", "properties": { - "authMethod": { + "dashboard_identifier": { "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" + "description": "Identifier of the dashboard that generated this exposure" }, - "baseBranch": { + "deduplication_name": { "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" + "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false + "exposure": { + "$ref": "#/components/schemas/DbtExposure" + } + }, + "required": [ + "dashboard_identifier", + "deduplication_name", + "exposure" + ] + }, + "DbtExposure": { + "type": "object", + "properties": { + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of dbt model references (e.g. ref('model_name'))", + "example": [ + "ref('orders')", + "ref('customers')" + ] }, - "cloneUrl": { + "label": { "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false + "description": "Original dashboard name" }, - "gitServiceProvider": { + "name": { "type": "string", - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" + "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", + "example": "my_dashboard" }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." + "owner": { + "$ref": "#/components/schemas/DbtExposureOwner" }, - "requirePullRequest": { + "type": { "type": "string", "enum": [ - "always", - "users-only", - "never" + "dashboard", + "notebook", + "analysis", + "ml", + "application" ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" + "description": "Type of the exposure", + "example": "dashboard" }, - "sshUrl": { + "url": { "type": "string", - "deprecated": true, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository." - }, - "webUrl": { - "type": [ - "string", - "null" - ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" - }, - "webhookSecret": { + "description": "URL of the dashboard" + } + }, + "required": [ + "depends_on", + "name", + "owner", + "type" + ], + "description": "The dbt exposure for this dashboard." + }, + "DbtExposureOwner": { + "type": "object", + "properties": { + "email": { "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + "description": "Email of the dashboard owner" }, - "webhookUrl": { + "name": { "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." + "description": "Name of the dashboard owner" } }, "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" + "email", + "name" ] }, - "ModelsGitUpdateBody": { + "ModelsBranchDbtBody": { "type": "object", "properties": { - "authMethod": { + "dbt_environment_id": { "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method to change to.", - "example": "ssh" + "format": "uuid", + "description": "ID of the dbt environment to activate on this branch", + "example": "123e4567-e89b-12d3-a456-426614174000" }, - "baseBranch": { + "dbt_git_branch": { "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" + "description": "Git branch to associate with the dbt environment", + "example": "feature/new-metrics" + } + }, + "required": [ + "dbt_environment_id" + ] + }, + "ModelsMergeBranchResponse": { + "type": "object", + "properties": { + "failed_drafts_count": { + "type": "number", + "description": "Number of drafts that failed to publish" }, - "branchPerPullRequest": { + "git_synced": { "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni", - "example": false + "description": "Whether git was synced" }, - "cloneUrl": { - "type": "string", - "minLength": 1, - "description": "Clone URL of the git repository (SSH or HTTPS).", - "example": "git@github.com:org/repo.git" + "published_drafts_count": { + "type": "number", + "description": "Number of drafts published" }, - "gitFollower": { + "success": { "type": "boolean", - "description": "If true, the shared model will be read-only", - "example": false - }, - "gitServiceProvider": { - "type": "string", - "enum": [ - "github", - "gitlab", - "azure_devops", - "bitbucket", - "bitbucket_datacenter", - "auto" - ], - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": "string", - "description": "Path to model files in the repository", - "example": "my_model" - }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "description": "Controls when pull requests are required", - "example": "users-only" - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", - "example": "git@github.com:org/repo.git", - "deprecated": true - }, - "token": { - "type": "string", - "maxLength": 1000, - "pattern": "^[a-zA-Z0-9_\\-.]+$", - "description": "HTTPS token for authentication (deploy token value, PAT, etc.)." - }, - "webUrl": { - "type": "string", - "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", - "example": "https://github.com/org/repo" + "description": "Whether the merge succeeded" } - } + }, + "required": [ + "failed_drafts_count", + "git_synced", + "published_drafts_count", + "success" + ] }, - "ModelsGitDeleteResponse": { + "ModelsMergeBranchBody": { "type": "object", "properties": { - "message": { + "commit_message": { "type": "string", - "description": "Success message", - "example": "Git repository unlinked successfully" + "description": "Custom commit message for git sync" }, - "success": { + "delete_branch": { "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + "default": false, + "description": "Delete the branch after merging" + }, + "force_override_git_settings": { + "type": "boolean", + "default": false, + "description": "Override PR-required or git-follower settings" + }, + "publish_drafts": { + "type": "boolean", + "default": true, + "description": "Publish branch-attached drafts" } - }, - "required": [ - "message", - "success" - ] + } }, - "ModelsGitSyncResponse": { + "ModelsCommitResponse": { "type": "object", "properties": { - "didSync": { + "did_sync": { "type": "boolean", - "description": "Whether a sync operation was performed" + "description": "Whether a sync operation was performed against git" }, - "gitSha": { + "git_sha": { "type": [ "string", "null" ], - "description": "The git SHA after the sync operation" + "description": "The git SHA of the commit that was pushed (null if no commit was needed)" }, - "inSync": { + "in_sync": { "type": "boolean", - "description": "Whether the model is currently in sync with git" + "description": "Whether the branch is in sync with git after the operation" }, - "message": { - "type": "string", - "description": "Human-readable message about the sync status" + "pr_url": { + "type": [ + "string", + "null" + ], + "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." } }, "required": [ - "didSync", - "gitSha", - "inSync", - "message" + "did_sync", + "git_sha", + "in_sync", + "pr_url" ] }, - "ModelsGitSyncBody": { + "ModelsCommitBody": { "type": "object", "properties": { - "commitMessage": { + "allow_branch_exists": { + "type": "boolean", + "default": true, + "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", + "example": true + }, + "branch_id": { "type": "string", - "description": "Optional commit message for the git sync operation", - "example": "Update model schema" + "format": "uuid", + "description": "UUID of the branch to commit.", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "commit_message": { + "type": "string", + "minLength": 1, + "description": "Commit message for the git commit.", + "example": "Add new orders view" + }, + "require_branch_exists": { + "type": "boolean", + "default": false, + "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", + "example": false } - } + }, + "required": [ + "branch_id", + "commit_message" + ] }, - "ModelsContentValidatorGetResponse": { + "ModelsCacheResetResponse": { "type": "object", "properties": { - "branch": { - "type": [ - "object", - "null" - ], + "cache_reset": { + "type": "object", "properties": { - "id": { - "type": "string", - "description": "Branch UUID" - }, - "name": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "Creation timestamp" + }, + "model_id": { "type": "string", - "description": "Branch name" + "description": "Model ID" + }, + "policy_name": { + "type": "string", + "description": "Cache policy name" + }, + "reset_at": { + "type": [ + "string", + "null" + ], + "description": "Reset timestamp" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "Last update timestamp" } }, "required": [ - "id", - "name" + "created_at", + "model_id", + "policy_name", + "reset_at", + "updated_at" ], - "description": "Branch info (present if branch_id was specified)" - }, - "content": { - "type": "array", - "items": {}, - "description": "Documents with their validation results" + "description": "Cache reset details" }, - "model_id": { - "type": "string", - "description": "Model UUID" + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" } }, "required": [ - "branch", - "content", - "model_id" + "cache_reset", + "success" ] }, - "ContentFilterMode": { - "type": "string", - "enum": [ - "ALL", - "WITH_ISSUES", - "NO_ISSUES" - ], - "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors." - }, - "ModelsContentValidatorReplaceResponse": { + "ModelsCacheResetBody": { "type": "object", "properties": { - "replaced_dashboard_filters_count": { - "type": "integer", - "description": "Number of dashboard filters replaced" - }, - "replaced_documents_count": { - "type": "integer", - "description": "Number of documents modified" - }, - "replaced_queries_count": { - "type": "integer", - "description": "Number of queries replaced" - }, - "replaced_workbook_models_count": { - "type": "integer", - "description": "Number of workbook models replaced" - }, - "skipped_pr_required_count": { - "type": "integer", - "description": "Number of documents skipped due to pull request requirements" + "resetAt": { + "type": "string", + "description": "ISO-8601 timestamp for when to reset the cache", + "example": "2024-01-15T12:00:00Z" } - }, - "required": [ - "replaced_dashboard_filters_count", - "replaced_documents_count", - "replaced_queries_count", - "replaced_workbook_models_count", - "skipped_pr_required_count" - ] + } }, - "ModelsContentValidatorReplaceBody": { + "ModelsGitGetResponse": { "type": "object", "properties": { - "branch_id": { + "authMethod": { "type": "string", - "description": "Optional branch ID" + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" }, - "creator_id": { + "baseBranch": { "type": "string", - "format": "uuid", - "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." + "description": "The target branch for Omni pull requests", + "example": "main" }, - "find": { - "type": "string", - "minLength": 1, - "description": "The string to find" + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false }, - "find_or_replace_type": { + "cloneUrl": { "type": "string", - "enum": [ - "FIELD", - "TOPIC", - "VIEW" - ], - "description": "Type of find/replace operation." - }, - "folder_paths": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Restrict replacement to documents in matching folder paths (prefix match). Documents with no folder are excluded unless \"\" is specified." + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" }, - "include_personal_folders": { + "gitFollower": { "type": "boolean", - "default": false, - "description": "Whether to include personal folders" + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false }, - "labels": { + "gitServiceProvider": { "type": "string", - "description": "Comma-separated label names to scope replacement. Unknown labels return 400." + "description": "The git provider type", + "example": "github" }, - "only_in_workbook_id": { + "modelPath": { + "type": [ + "string", + "null" + ], + "description": "Path to model files in the repository", + "example": "omni/my_model" + }, + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { "type": "string", - "description": "Optional workbook ID to limit the replace scope" + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" }, - "replacement": { + "sshUrl": { "type": "string", - "minLength": 1, - "description": "The replacement string" - } - }, - "required": [ - "find", - "find_or_replace_type", - "replacement" - ] - }, - "ModelYamlResponse": { - "type": "object", - "properties": { - "checksums": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Checksums for each file" + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." }, - "files": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "YAML content for each file" + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" }, - "version": { - "type": "number", - "description": "Model version number" + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" }, - "viewNames": { - "type": "object", - "additionalProperties": {}, - "description": "View name mappings" + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." } }, "required": [ - "files", - "version" + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" ] }, - "ModelYamlCreateRequestBody": { + "ModelsGitCreateResponse": { "type": "object", "properties": { - "branchId": { + "authMethod": { "type": "string", - "format": "uuid", - "description": "Branch ID for branch-aware operations" + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" }, - "fileName": { + "baseBranch": { "type": "string", - "minLength": 1, - "description": "File name to create or update" - }, - "mode": { - "type": "string", - "enum": [ - "combined", - "extension", - "staged", - "merged", - "fully-resolved" - ], - "default": "combined", - "description": "IDE mode for YAML operations" + "description": "The target branch for Omni pull requests", + "example": "main" }, - "commitMessage": { - "type": "string", - "description": "Commit message for git sync" + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false }, - "fetchedAtMillis": { - "type": "number", - "description": "Timestamp when the file was fetched" + "cloneUrl": { + "type": "string", + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" }, - "fullyResolved": { + "gitFollower": { "type": "boolean", - "default": false, - "description": "Treat the posted YAML as fully resolved (with the extends chain expanded). Only valid with mode=combined." + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false }, - "previousChecksum": { + "gitServiceProvider": { "type": "string", - "description": "Previous checksum for conflict detection" + "description": "The git provider type", + "example": "github" }, - "yaml": { - "type": "string", - "description": "YAML content for the file" - } - }, - "required": [ - "fileName", - "yaml" - ], - "additionalProperties": false - }, - "AiAgentActionsResponse": { - "type": "object", - "properties": { - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AiAgentAction" - }, - "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." - } - }, - "required": [ - "records" - ] - }, - "AiAgentAction": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "enum": [ - "sample", - "skill" + "modelPath": { + "type": [ + "string", + "null" ], - "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", - "example": "skill" + "description": "Path to model files in the repository", + "example": "omni/my_model" }, - "label": { + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { "type": "string", - "description": "Short, human-readable name for the action — chip text in client UIs and the visible \"prompt\" on the answer card.", - "example": "Revenue trends" + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" }, - "prompt": { + "sshUrl": { "type": "string", - "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", - "example": "Skill:\nShow me the recent revenue trends grouped by month…" - } - }, - "required": [ - "kind", - "label", - "prompt" - ] - }, - "QueryRunResponse": { - "type": "object", - "properties": { - "completedQueries": { - "type": "array", - "items": {}, - "description": "Queries that completed synchronously with their results." + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." }, - "jobIds": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for results.", - "example": [ - "job_abc123", - "job_def456" - ] + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" }, - "plan": { - "description": "Query execution plan (only present if planOnly is true)." - } - } - }, - "QueryTimeoutResponse": { - "type": "object", - "properties": { - "detail": { + "webhookSecret": { "type": "string", - "description": "Error message indicating the query timed out.", - "example": "Query timed out" - }, - "remaining_job_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Job IDs for queries that have not yet completed. Use /api/v1/query/wait to poll for results." + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" }, - "timed_out": { - "type": "boolean", - "enum": [ - true - ], - "description": "Always true for timeout responses.", - "example": true + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." } }, "required": [ - "detail", - "timed_out" + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" ] }, - "QueryRunBody": { + "ModelsGitCreateBody": { "type": "object", "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional model branch to run the query against. Must belong to the same shared model as the query. When omitted, the query runs against the shared model. Takes precedence over the legacy `?branch_id=` URL query parameter.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "cache": { + "authMethod": { "type": "string", "enum": [ - "disabled", - "normal", - "refresh", - "refresh_all" + "ssh", + "https_token" ], - "description": "Cache policy for query execution. Controls whether to use cached results.", - "example": "normal" + "default": "ssh", + "description": "Authentication method. \"ssh\" for deploy key (default), \"https_token\" for deploy token/PAT.", + "example": "ssh" }, - "formatResults": { - "type": "boolean", - "description": "Whether to format result values (e.g., apply number formatting). Only valid when resultType is specified." + "baseBranch": { + "type": "string", + "default": "main", + "description": "The target branch for Omni pull requests. Defaults to \"main\"", + "example": "main" }, - "planOnly": { + "branchPerPullRequest": { "type": "boolean", "default": false, - "description": "If true, returns only the query execution plan without running the query." + "description": "If true, all pull requests will create a branch in Omni. Defaults to false", + "example": false }, - "query": { - "description": "The semantic query definition including fields, filters, sorts, and other query parameters." + "cloneUrl": { + "type": "string", + "minLength": 1, + "description": "Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth.", + "example": "git@github.com:org/repo.git" }, - "resultType": { + "gitFollower": { + "type": "boolean", + "default": false, + "description": "If true, the shared model will be read-only. Defaults to false", + "example": false + }, + "gitServiceProvider": { "type": "string", "enum": [ - "csv", - "json", - "xlsx" + "github", + "gitlab", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "auto" ], - "description": "Output format for the results. If not specified, returns base64-encoded Arrow format." + "default": "auto", + "description": "The git provider type. Use \"auto\" for automatic detection. Defaults to \"auto\"", + "example": "auto" }, - "userId": { + "modelPath": { "type": "string", - "format": "uuid", - "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter — this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - } - }, - "QueryWaitResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": {}, - "description": "Array of completed query results. Each result contains the query data or an error." - } - }, - "required": [ - "results" - ] - }, - "SchedulesListItem": { - "type": "object", - "properties": { - "alert": { - "type": "object", - "properties": { - "conditionQueryName": { - "type": [ - "string", - "null" - ], - "description": "Name of the query used for alert condition" - }, - "conditionType": { - "type": "string", - "description": "Type of alert condition: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" - } - }, - "required": [ - "conditionQueryName", - "conditionType" - ], - "description": "Alert configuration (only present for alert-type schedules)" + "description": "Path to model files in the repository. Defaults to omni/. Use a plain name (e.g., \"my_model\") for omni/my_model, or a leading slash for a custom path (e.g., \"/bi/models/sales\")", + "example": "my_model" }, - "content": { + "requirePullRequest": { "type": "string", - "description": "Content type: dashboard or tile", - "example": "dashboard" + "enum": [ + "always", + "users-only", + "never" + ], + "default": "never", + "description": "Controls when pull requests are required. Defaults to \"never\"", + "example": "never" }, - "dashboardName": { + "sshUrl": { "type": "string", - "description": "Name of the dashboard", - "example": "Weekly Sales Report" + "minLength": 1, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", + "example": "git@github.com:org/repo.git", + "deprecated": true }, - "destinationType": { + "token": { "type": "string", - "description": "Delivery destination type: email, slack, webhook, sftp, s3, google_sheets", - "example": "email" + "maxLength": 1000, + "pattern": "^[a-zA-Z0-9_\\-.]+$", + "description": "HTTPS token for authentication (deploy token value, PAT, etc.). Required when authMethod is \"https_token\"." }, - "disabledAt": { - "type": [ - "string", - "null" + "webUrl": { + "type": "string", + "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", + "example": "https://github.com/org/repo" + } + } + }, + "ModelsGitUpdateResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" ], - "format": "date-time", - "description": "Timestamp when the schedule was paused (null if active)" + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" }, - "format": { + "baseBranch": { "type": "string", - "description": "Output format: pdf, png, csv, xlsx, json, link_only", - "example": "pdf" + "description": "The target branch for Omni pull requests", + "example": "main" }, - "id": { + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { "type": "string", - "format": "uuid", - "description": "Unique identifier for the schedule" + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" }, - "identifier": { + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false + }, + "gitServiceProvider": { "type": "string", - "description": "Dashboard identifier", - "example": "12db1a0a" + "description": "The git provider type", + "example": "github" }, - "lastCompletedAt": { + "modelPath": { "type": [ "string", "null" ], - "format": "date-time", - "description": "Timestamp of last completed delivery" + "description": "Path to model files in the repository", + "example": "omni/my_model" }, - "lastStatus": { + "publicKey": { "type": [ "string", "null" ], - "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" - }, - "name": { - "type": "string", - "description": "Name of the schedule", - "example": "Weekly Sales Report" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the schedule owner" + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." }, - "ownerName": { + "requirePullRequest": { "type": "string", - "description": "Display name of the schedule owner", - "example": "John Doe" - }, - "recipientCount": { - "type": "number", - "description": "Number of recipients (-1 for non-email destinations)", - "example": 5 + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" }, - "schedule": { + "sshUrl": { "type": "string", - "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", - "example": "0 9 ? * MON *" - }, - "slackRecipientType": { - "type": [ - "string", - "null" - ], - "description": "Slack recipient type: Channel or Users (null for non-Slack)" + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." }, - "systemDisabledAt": { + "webUrl": { "type": [ "string", "null" ], - "format": "date-time", - "description": "Timestamp when system disabled the schedule (null if not system-disabled)" + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" }, - "systemDisabledReason": { - "type": [ - "string", - "null" - ], - "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" }, - "timezone": { + "webhookUrl": { "type": "string", - "description": "IANA timezone for the schedule", - "example": "America/New_York" + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." } }, "required": [ - "content", - "dashboardName", - "destinationType", - "disabledAt", - "format", - "id", - "identifier", - "lastCompletedAt", - "lastStatus", - "name", - "ownerId", - "ownerName", - "recipientCount", - "schedule", - "slackRecipientType", - "systemDisabledAt", - "systemDisabledReason", - "timezone" + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" ] }, - "SchedulesGetResponse": { + "ModelsGitUpdateBody": { "type": "object", "properties": { - "conditionQueryMapKey": { - "type": [ - "string", - "null" - ], - "description": "Query key used for alert condition (null for standard schedules)" - }, - "conditionType": { - "type": [ - "string", - "null" + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" ], - "description": "Alert condition type: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + "description": "Authentication method to change to.", + "example": "ssh" }, - "createdAt": { + "baseBranch": { "type": "string", - "format": "date-time", - "description": "Creation timestamp" + "description": "The target branch for Omni pull requests", + "example": "main" }, - "destinations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchedulesGetDestination" - }, - "description": "Delivery destination configurations" + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni", + "example": false }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp when the schedule was paused (null if active)" - }, - "entityId": { + "cloneUrl": { "type": "string", - "description": "ID of the associated dashboard" + "minLength": 1, + "description": "Clone URL of the git repository (SSH or HTTPS).", + "example": "git@github.com:org/repo.git" }, - "fanOut": { + "gitFollower": { "type": "boolean", - "description": "Whether personalized fan-out delivery is enabled", + "description": "If true, the shared model will be read-only", "example": false }, - "filterConfig": { - "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." - }, - "id": { + "gitServiceProvider": { "type": "string", - "format": "uuid", - "description": "Schedule UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "killJobsOnFailure": { - "type": "boolean", - "description": "Whether to stop the job if any queries fail", - "example": false - }, - "metadata": { - "description": "Schedule metadata including format options and delivery settings" + "enum": [ + "github", + "gitlab", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "auto" + ], + "description": "The git provider type", + "example": "github" }, - "name": { + "modelPath": { "type": "string", - "description": "Schedule name", - "example": "Weekly Sales Report" + "description": "Path to model files in the repository", + "example": "my_model" }, - "organizationId": { + "requirePullRequest": { "type": "string", - "format": "uuid", - "description": "Organization UUID" + "enum": [ + "always", + "users-only", + "never" + ], + "description": "Controls when pull requests are required", + "example": "users-only" }, - "owner": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Schedule owner name" - } - }, - "required": [ - "name" - ] + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", + "example": "git@github.com:org/repo.git", + "deprecated": true }, - "ownerId": { + "token": { "type": "string", - "format": "uuid", - "description": "User ID of the schedule owner" + "maxLength": 1000, + "pattern": "^[a-zA-Z0-9_\\-.]+$", + "description": "HTTPS token for authentication (deploy token value, PAT, etc.)." }, - "schedule": { + "webUrl": { "type": "string", - "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", - "example": "0 9 ? * MON *" + "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", + "example": "https://github.com/org/repo" + } + } + }, + "ModelsGitDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "Git repository unlinked successfully" }, - "systemDisabledAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp when the system disabled the schedule" + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ] + }, + "ModelsGitSyncResponse": { + "type": "object", + "properties": { + "didSync": { + "type": "boolean", + "description": "Whether a sync operation was performed" }, - "systemDisabledReason": { + "gitSha": { "type": [ "string", "null" ], - "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + "description": "The git SHA after the sync operation" }, - "timezone": { - "type": "string", - "description": "IANA timezone for the schedule", - "example": "America/New_York" + "inSync": { + "type": "boolean", + "description": "Whether the model is currently in sync with git" }, - "updatedAt": { + "message": { "type": "string", - "format": "date-time", - "description": "Last update timestamp" + "description": "Human-readable message about the sync status" } }, "required": [ - "conditionQueryMapKey", - "conditionType", - "createdAt", - "destinations", - "disabledAt", - "entityId", - "fanOut", - "id", - "killJobsOnFailure", - "name", - "organizationId", - "owner", - "ownerId", - "schedule", - "systemDisabledAt", - "systemDisabledReason", - "timezone", - "updatedAt" + "didSync", + "gitSha", + "inSync", + "message" ] }, - "SchedulesGetDestination": { + "ModelsGitSyncBody": { "type": "object", "properties": { - "format": { - "type": "string", - "description": "Output format: pdf, png, csv, xlsx, json, link_only", - "example": "pdf" - }, - "id": { + "commitMessage": { "type": "string", - "format": "uuid", - "description": "Destination UUID" - }, - "lastCompletedAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp of last completed delivery" - }, - "lastStatus": { + "description": "Optional commit message for the git sync operation", + "example": "Update model schema" + } + } + }, + "ModelsContentValidatorGetResponse": { + "type": "object", + "properties": { + "branch": { "type": [ - "string", + "object", "null" ], - "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" - }, - "metadata": { - "description": "Destination-specific configuration (type, recipients, credentials, etc.)" - }, - "recipients": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchedulesGetRecipient" + "properties": { + "id": { + "type": "string", + "description": "Branch UUID" + }, + "name": { + "type": "string", + "description": "Branch name" + } }, - "description": "Individual email recipients" + "required": [ + "id", + "name" + ], + "description": "Branch info (present if branch_id was specified)" }, - "userGroupRecipients": { + "content": { "type": "array", "items": {}, - "description": "User group recipients" + "description": "Documents with their validation results" + }, + "model_id": { + "type": "string", + "description": "Model UUID" } }, "required": [ - "format", - "id", - "lastCompletedAt", - "lastStatus", - "recipients", - "userGroupRecipients" + "branch", + "content", + "model_id" ] }, - "SchedulesGetRecipient": { + "ContentFilterMode": { + "type": "string", + "enum": [ + "ALL", + "WITH_ISSUES", + "NO_ISSUES" + ], + "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors." + }, + "ModelsContentValidatorReplaceResponse": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Recipient ID" + "replaced_dashboard_filters_count": { + "type": "integer", + "description": "Number of dashboard filters replaced" }, - "membership": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Recipient email" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Recipient name" - } - }, - "required": [ - "email", - "name" - ] - } - }, - "required": [ - "user" - ] + "replaced_documents_count": { + "type": "integer", + "description": "Number of documents modified" }, - "membershipId": { - "type": "string", - "format": "uuid", - "description": "Membership ID" + "replaced_queries_count": { + "type": "integer", + "description": "Number of queries replaced" + }, + "replaced_workbook_models_count": { + "type": "integer", + "description": "Number of workbook models replaced" + }, + "skipped_pr_required_count": { + "type": "integer", + "description": "Number of documents skipped due to pull request requirements" } }, "required": [ - "id", - "membership", - "membershipId" + "replaced_dashboard_filters_count", + "replaced_documents_count", + "replaced_queries_count", + "replaced_workbook_models_count", + "skipped_pr_required_count" ] }, - "SchedulesRecipientsGetResponse": { + "ModelsContentValidatorReplaceBody": { "type": "object", "properties": { - "recipients": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EmailRecipient" - }, - "description": "List of individual recipients (for email destinations)." + "branch_id": { + "type": "string", + "description": "Optional branch ID" }, - "type": { + "creator_id": { + "type": "string", + "format": "uuid", + "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." + }, + "find": { + "type": "string", + "minLength": 1, + "description": "The string to find" + }, + "find_or_replace_type": { "type": "string", "enum": [ - "email", - "google_sheets", - "s3", - "sftp", - "slack", - "webhook" + "FIELD", + "TOPIC", + "VIEW" ], - "description": "The schedule's destination type.", - "example": "email" + "description": "Type of find/replace operation." }, - "userGroupRecipients": { + "folder_paths": { "type": "array", "items": { - "$ref": "#/components/schemas/UserGroupRecipient" + "type": "string" }, - "description": "List of user group recipients (for email destinations)." + "description": "Restrict replacement to documents in matching folder paths (prefix match). Documents with no folder are excluded unless \"\" is specified." + }, + "include_personal_folders": { + "type": "boolean", + "default": false, + "description": "Whether to include personal folders" + }, + "labels": { + "type": "string", + "description": "Comma-separated label names to scope replacement. Unknown labels return 400." + }, + "only_in_workbook_id": { + "type": "string", + "description": "Optional workbook ID to limit the replace scope" + }, + "replacement": { + "type": "string", + "minLength": 1, + "description": "The replacement string" } }, "required": [ - "type" + "find", + "find_or_replace_type", + "replacement" ] }, - "EmailRecipient": { + "ModelYamlResponse": { "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Recipient's email address.", - "example": "user@example.com" + "checksums": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Checksums for each file" }, - "id": { - "type": "string", - "description": "Unique identifier for the recipient." + "files": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "YAML content for each file" }, - "name": { - "type": "string", - "description": "Recipient's display name.", - "example": "John Doe" + "version": { + "type": "number", + "description": "Model version number" + }, + "viewNames": { + "type": "object", + "additionalProperties": {}, + "description": "View name mappings" } }, "required": [ - "email", - "id", - "name" + "files", + "version" ] }, - "UserGroupRecipient": { + "ModelYamlCreateRequestBody": { "type": "object", "properties": { - "id": { + "branchId": { "type": "string", - "description": "User group ID." + "format": "uuid", + "description": "Branch ID for branch-aware operations" }, - "name": { + "fileName": { "type": "string", - "description": "User group name.", - "example": "Sales Team" + "minLength": 1, + "description": "File name to create or update" }, - "recipients": { + "mode": { + "type": "string", + "enum": [ + "combined", + "extension", + "staged", + "merged", + "fully-resolved" + ], + "default": "combined", + "description": "IDE mode for YAML operations" + }, + "commitMessage": { + "type": "string", + "description": "Commit message for git sync" + }, + "fetchedAtMillis": { + "type": "number", + "description": "Timestamp when the file was fetched" + }, + "fullyResolved": { + "type": "boolean", + "default": false, + "description": "Treat the posted YAML as fully resolved (with the extends chain expanded). Only valid with mode=combined." + }, + "previousChecksum": { + "type": "string", + "description": "Previous checksum for conflict detection" + }, + "yaml": { + "type": "string", + "description": "YAML content for the file" + } + }, + "required": [ + "fileName", + "yaml" + ], + "additionalProperties": false + }, + "AiAgentActionsResponse": { + "type": "object", + "properties": { + "records": { "type": "array", "items": { - "$ref": "#/components/schemas/EmailRecipient" + "$ref": "#/components/schemas/AiAgentAction" }, - "description": "List of recipients in the user group." + "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." } }, "required": [ - "id", - "name", - "recipients" + "records" ] }, - "SchedulesAddRecipientsResponse": { + "AiAgentAction": { "type": "object", "properties": { - "addedGroupRecipientsCount": { - "type": "number", - "description": "Number of user group recipients added.", - "example": 1 + "kind": { + "type": "string", + "enum": [ + "sample", + "skill" + ], + "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", + "example": "skill" }, - "addedRecipientsCount": { - "type": "number", - "description": "Number of individual recipients added.", - "example": 2 + "label": { + "type": "string", + "description": "Short, human-readable name for the action — chip text in client UIs and the visible \"prompt\" on the answer card.", + "example": "Revenue trends" }, - "success": { - "type": "boolean", - "description": "Whether the operation was successful.", - "example": true + "prompt": { + "type": "string", + "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", + "example": "Skill:\nShow me the recent revenue trends grouped by month…" } }, "required": [ - "addedGroupRecipientsCount", - "addedRecipientsCount", - "success" + "kind", + "label", + "prompt" ] }, - "SchedulesAddRecipientsBody": { + "QueryRunResponse": { "type": "object", "properties": { - "emails": { + "completedQueries": { "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of email addresses to add as recipients.", - "example": [ - "user@example.com" - ] + "items": {}, + "description": "Queries that completed synchronously with their results." }, - "userGroupIds": { + "jobIds": { "type": "array", "items": { - "type": "string", - "format": "uuid" + "type": "string" }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to add as recipients.", + "description": "Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for results.", "example": [ - "123e4567-e89b-12d3-a456-426614174000" + "job_abc123", + "job_def456" ] }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user UUIDs to add as recipients. Use the List users and List embed users endpoints to retrieve user IDs.", - "example": [ - "987fcdeb-51a2-43d7-9b56-254415f67890" - ] + "plan": { + "description": "Query execution plan (only present if planOnly is true)." } } }, - "SchedulesRemoveRecipientsResponse": { + "QueryTimeoutResponse": { "type": "object", "properties": { - "removedGroupRecipientsCount": { - "type": "number", - "description": "Number of user group recipients removed.", - "example": 1 + "detail": { + "type": "string", + "description": "Error message indicating the query timed out.", + "example": "Query timed out" }, - "removedRecipientsCount": { - "type": "number", - "description": "Number of individual recipients removed.", - "example": 2 + "remaining_job_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Job IDs for queries that have not yet completed. Use /api/v1/query/wait to poll for results." }, - "success": { + "timed_out": { "type": "boolean", - "description": "Whether the operation was successful.", + "enum": [ + true + ], + "description": "Always true for timeout responses.", "example": true } }, "required": [ - "removedGroupRecipientsCount", - "removedRecipientsCount", - "success" + "detail", + "timed_out" ] }, - "SchedulesRemoveRecipientsBody": { + "QueryRunBody": { "type": "object", "properties": { - "emails": { - "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of recipient email addresses to remove from the scheduled task.", - "example": [ - "user@example.com" - ] + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional model branch to run the query against. Must belong to the same shared model as the query. When omitted, the query runs against the shared model. Takes precedence over the legacy `?branch_id=` URL query parameter.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to remove as recipients.", - "example": [ - "123e4567-e89b-12d3-a456-426614174000" - ] + "cache": { + "type": "string", + "enum": [ + "disabled", + "normal", + "refresh", + "refresh_all" + ], + "description": "Cache policy for query execution. Controls whether to use cached results.", + "example": "normal" }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of recipient user UUIDs to remove from the scheduled task. Use the List users and List embed users endpoints to retrieve user IDs.", - "example": [ - "987fcdeb-51a2-43d7-9b56-254415f67890" - ] + "formatResults": { + "type": "boolean", + "description": "Whether to format result values (e.g., apply number formatting). Only valid when resultType is specified." + }, + "planOnly": { + "type": "boolean", + "default": false, + "description": "If true, returns only the query execution plan without running the query." + }, + "query": { + "description": "The semantic query definition including fields, filters, sorts, and other query parameters." + }, + "resultType": { + "type": "string", + "enum": [ + "csv", + "json", + "xlsx" + ], + "description": "Output format for the results. If not specified, returns base64-encoded Arrow format." + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter — this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", + "example": "550e8400-e29b-41d4-a716-446655440000" } } }, - "SchedulesTransferOwnershipBody": { + "QueryWaitResponse": { "type": "object", "properties": { - "userId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the user to transfer schedule ownership to. Use the List users endpoint to retrieve user IDs. The new owner must be a member of the same organization, not be the current owner, and have permission to view the dashboard associated with the schedule.", - "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + "results": { + "type": "array", + "items": {}, + "description": "Array of completed query results. Each result contains the query data or an error." } }, "required": [ - "userId" + "results" ] }, - "ScimUsersListResponse": { + "SchedulesListItem": { "type": "object", "properties": { - "Resources": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ScimUserResponse" + "alert": { + "type": "object", + "properties": { + "conditionQueryName": { + "type": [ + "string", + "null" + ], + "description": "Name of the query used for alert condition" + }, + "conditionType": { + "type": "string", + "description": "Type of alert condition: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + } }, - "description": "List of SCIM users" + "required": [ + "conditionQueryName", + "conditionType" + ], + "description": "Alert configuration (only present for alert-type schedules)" }, - "itemsPerPage": { - "type": "number", - "description": "Items per page" + "content": { + "type": "string", + "description": "Content type: dashboard or tile", + "example": "dashboard" }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" + "dashboardName": { + "type": "string", + "description": "Name of the dashboard", + "example": "Weekly Sales Report" }, - "startIndex": { - "type": "number", - "description": "Start index (1-based)" + "destinationType": { + "type": "string", + "description": "Delivery destination type: email, slack, webhook, sftp, s3, google_sheets", + "example": "email" }, - "totalResults": { - "type": "number", - "description": "Total number of results" - } - }, - "required": [ - "Resources", - "itemsPerPage", - "schemas", - "startIndex", - "totalResults" - ] - }, - "ScimUserResponse": { - "type": "object", - "properties": { - "active": { - "type": "boolean", - "description": "Whether the user is active" + "disabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the schedule was paused (null if active)" }, - "displayName": { + "format": { "type": "string", - "description": "Display name" + "description": "Output format: pdf, png, csv, xlsx, json, link_only", + "example": "pdf" }, "id": { "type": "string", "format": "uuid", - "description": "SCIM user ID" - }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" + "description": "Unique identifier for the schedule" }, - "userName": { + "identifier": { "type": "string", - "format": "email", - "description": "Username (email)" - } - }, - "required": [ - "active", - "displayName", - "id", - "schemas", - "userName" - ] - }, - "ScimUserCreateRequest": { - "type": "object", - "properties": { - "displayName": { + "description": "Dashboard identifier", + "example": "12db1a0a" + }, + "lastCompletedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp of last completed delivery" + }, + "lastStatus": { + "type": [ + "string", + "null" + ], + "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" + }, + "name": { "type": "string", - "description": "Display name of the user", - "example": "John Doe" + "description": "Name of the schedule", + "example": "Weekly Sales Report" }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Omni user attributes" + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the schedule owner" }, - "userName": { + "ownerName": { "type": "string", - "format": "email", - "description": "Email address (username) of the user", - "example": "user@example.com" - } - }, - "required": [ - "displayName", - "userName" - ] - }, - "ScimUserPutRequest": { - "type": "object", - "properties": { - "active": { - "type": "boolean", - "default": true, - "description": "Whether the user is active" + "description": "Display name of the schedule owner", + "example": "John Doe" }, - "displayName": { + "recipientCount": { + "type": "number", + "description": "Number of recipients (-1 for non-email destinations)", + "example": 5 + }, + "schedule": { "type": "string", - "description": "Display name of the user" + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" }, - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Enterprise SCIM user attributes" + "slackRecipientType": { + "type": [ + "string", + "null" + ], + "description": "Slack recipient type: Channel or Users (null for non-Slack)" }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Omni user attributes" + "systemDisabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when system disabled the schedule (null if not system-disabled)" }, - "userName": { + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + }, + "timezone": { "type": "string", - "format": "email", - "description": "Email address (username) of the user", - "example": "user@example.com" + "description": "IANA timezone for the schedule", + "example": "America/New_York" } }, "required": [ - "userName" + "content", + "dashboardName", + "destinationType", + "disabledAt", + "format", + "id", + "identifier", + "lastCompletedAt", + "lastStatus", + "name", + "ownerId", + "ownerName", + "recipientCount", + "schedule", + "slackRecipientType", + "systemDisabledAt", + "systemDisabledReason", + "timezone" ] }, - "ScimUserPatchRequest": { + "SchedulesGetResponse": { "type": "object", "properties": { - "Operations": { + "conditionQueryMapKey": { + "type": [ + "string", + "null" + ], + "description": "Query key used for alert condition (null for standard schedules)" + }, + "conditionType": { + "type": [ + "string", + "null" + ], + "description": "Alert condition type: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "Creation timestamp" + }, + "destinations": { "type": "array", "items": { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace", - "add", - "Add", - "Remove", - "remove" - ] - }, - "path": { - "type": "string" - }, - "value": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - } - }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - } - }, - "active": { - "type": "boolean" - }, - "displayName": { - "type": "string" - }, - "userName": { - "type": "string", - "format": "email" - } - } - } - ] - } - }, - "required": [ - "op", - "value" - ] - }, - "minItems": 1, - "description": "List of patch operations to apply" - }, - "schemas": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "urn:ietf:params:scim:api:messages:2.0:PatchOp" - ] - }, - "description": "SCIM schema URIs" - } - }, - "required": [ - "Operations", - "schemas" - ] - }, - "ScimGroupsListResponse": { - "type": "object", - "properties": { - "Resources": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ScimGroupResponse" + "$ref": "#/components/schemas/SchedulesGetDestination" }, - "description": "List of SCIM groups" + "description": "Delivery destination configurations" }, - "itemsPerPage": { - "type": "number", - "description": "Items per page" + "disabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the schedule was paused (null if active)" }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" + "entityId": { + "type": "string", + "description": "ID of the associated dashboard" }, - "startIndex": { - "type": "number", - "description": "Start index (1-based)" + "fanOut": { + "type": "boolean", + "description": "Whether personalized fan-out delivery is enabled", + "example": false }, - "totalResults": { - "type": "number", - "description": "Total number of results" - } - }, - "required": [ - "Resources", - "itemsPerPage", - "schemas", - "startIndex", - "totalResults" - ] - }, - "ScimGroupResponse": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "Group display name" + "filterConfig": { + "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." }, "id": { "type": "string", - "description": "SCIM group ID (miniUuid)" + "format": "uuid", + "description": "Schedule UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" }, - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Member display name" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "Member user ID" - } - }, - "required": [ - "display", - "value" - ] - }, - "description": "Group members" + "killJobsOnFailure": { + "type": "boolean", + "description": "Whether to stop the job if any queries fail", + "example": false }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" - } - }, - "required": [ - "displayName", - "id", - "schemas" - ] - }, - "ScimGroupsCreateBody": { - "type": "object", - "properties": { - "displayName": { + "metadata": { + "description": "Schedule metadata including format options and delivery settings" + }, + "name": { "type": "string", - "description": "Display name of the group", - "example": "Engineering Team" + "description": "Schedule name", + "example": "Weekly Sales Report" }, - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] + "organizationId": { + "type": "string", + "format": "uuid", + "description": "Organization UUID" + }, + "owner": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Schedule owner name" + } }, - "default": [], - "description": "List of group members" + "required": [ + "name" + ] + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the schedule owner" + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" + }, + "systemDisabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the system disabled the schedule" + }, + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for the schedule", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" } }, "required": [ - "displayName" + "conditionQueryMapKey", + "conditionType", + "createdAt", + "destinations", + "disabledAt", + "entityId", + "fanOut", + "id", + "killJobsOnFailure", + "name", + "organizationId", + "owner", + "ownerId", + "schedule", + "systemDisabledAt", + "systemDisabledReason", + "timezone", + "updatedAt" ] }, - "ScimGroupsReplaceBody": { + "SchedulesGetDestination": { "type": "object", "properties": { - "displayName": { + "format": { "type": "string", - "description": "Display name of the group", - "example": "Engineering Team" + "description": "Output format: pdf, png, csv, xlsx, json, link_only", + "example": "pdf" }, - "members": { + "id": { + "type": "string", + "format": "uuid", + "description": "Destination UUID" + }, + "lastCompletedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp of last completed delivery" + }, + "lastStatus": { + "type": [ + "string", + "null" + ], + "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" + }, + "metadata": { + "description": "Destination-specific configuration (type, recipients, credentials, etc.)" + }, + "recipients": { "type": "array", "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" + "$ref": "#/components/schemas/SchedulesGetRecipient" + }, + "description": "Individual email recipients" + }, + "userGroupRecipients": { + "type": "array", + "items": {}, + "description": "User group recipients" + } + }, + "required": [ + "format", + "id", + "lastCompletedAt", + "lastStatus", + "recipients", + "userGroupRecipients" + ] + }, + "SchedulesGetRecipient": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Recipient ID" + }, + "membership": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Recipient email" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Recipient name" + } }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "display", - "value" - ] + "required": [ + "email", + "name" + ] + } }, - "description": "List of group members" + "required": [ + "user" + ] + }, + "membershipId": { + "type": "string", + "format": "uuid", + "description": "Membership ID" } }, "required": [ - "displayName", - "members" + "id", + "membership", + "membershipId" ] }, - "ScimGroupsPatchBody": { + "SchedulesRecipientsGetResponse": { "type": "object", "properties": { - "Operations": { + "recipients": { "type": "array", "items": { - "anyOf": [ - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace" - ], - "description": "Operation type", - "example": "replace" - }, - "value": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "New display name", - "example": "Engineering Team" - }, - "id": { - "type": "string", - "description": "Group ID" - } - }, - "required": [ - "displayName" - ] - } - }, - "required": [ - "op", - "value" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "remove", - "Remove" - ], - "description": "Operation type", - "example": "remove" - }, - "path": { - "type": "string", - "pattern": "members\\[value eq \"(.{36})\"\\]", - "description": "SCIM path for member to remove", - "example": "members[value eq \"550e8400-e29b-41d4-a716-446655440000\"]" - } - }, - "required": [ - "op", - "path" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "add", - "Add" - ], - "description": "Operation type", - "example": "add" - }, - "path": { - "type": "string", - "enum": [ - "members" - ], - "description": "Path for members", - "example": "members" - }, - "value": { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] - } - } - }, - "required": [ - "op", - "path", - "value" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace" - ], - "description": "Operation type", - "example": "replace" - }, - "path": { - "type": "string", - "enum": [ - "members", - "displayName" - ], - "description": "Path for attribute to replace", - "example": "members" - }, - "value": { - "anyOf": [ - { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] - } - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "op", - "path", - "value" - ] - } - ] + "$ref": "#/components/schemas/EmailRecipient" }, - "description": "List of SCIM patch operations" + "description": "List of individual recipients (for email destinations)." }, - "schemas": { + "type": { + "type": "string", + "enum": [ + "email", + "google_sheets", + "s3", + "sftp", + "slack", + "webhook" + ], + "description": "The schedule's destination type.", + "example": "email" + }, + "userGroupRecipients": { "type": "array", "items": { - "type": "string", - "enum": [ - "urn:ietf:params:scim:api:messages:2.0:PatchOp" - ] + "$ref": "#/components/schemas/UserGroupRecipient" }, - "description": "SCIM schema URIs" + "description": "List of user group recipients (for email destinations)." } }, "required": [ - "Operations", - "schemas" + "type" ] }, - "DocumentExportResponse": { + "EmailRecipient": { "type": "object", "properties": { - "dashboard": { - "description": "Dashboard configuration and layout" - }, - "document": { - "type": "object", - "properties": { - "ephemeral": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "exportVersion": { - "type": "string" - }, - "fileUploads": { - "type": "object", - "additionalProperties": {} + "email": { + "type": "string", + "format": "email", + "description": "Recipient's email address.", + "example": "user@example.com" }, - "queryModels": { - "type": "object", - "additionalProperties": {} + "id": { + "type": "string", + "description": "Unique identifier for the recipient." }, - "workbookModel": {} + "name": { + "type": "string", + "description": "Recipient's display name.", + "example": "John Doe" + } }, "required": [ - "document", - "exportVersion", - "queryModels" + "email", + "id", + "name" ] }, - "DocumentImportResponse": { + "UserGroupRecipient": { "type": "object", "properties": { - "documentId": { + "id": { "type": "string", - "format": "uuid", - "description": "ID of the imported document" + "description": "User group ID." }, - "identifier": { + "name": { "type": "string", - "description": "Document identifier (miniUuid)" + "description": "User group name.", + "example": "Sales Team" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailRecipient" + }, + "description": "List of recipients in the user group." } }, "required": [ - "documentId", - "identifier" + "id", + "name", + "recipients" ] }, - "DocumentImportBody": { + "SchedulesAddRecipientsResponse": { "type": "object", "properties": { - "baseModelId": { - "type": "string", - "format": "uuid", - "description": "Base model ID for the imported document" + "addedGroupRecipientsCount": { + "type": "number", + "description": "Number of user group recipients added.", + "example": 1 }, - "dashboard": { - "description": "Dashboard export data" + "addedRecipientsCount": { + "type": "number", + "description": "Number of individual recipients added.", + "example": 2 }, - "document": { - "type": "object", - "properties": { - "ephemeral": { - "type": "string" - }, - "name": { - "type": "string" - } + "success": { + "type": "boolean", + "description": "Whether the operation was successful.", + "example": true + } + }, + "required": [ + "addedGroupRecipientsCount", + "addedRecipientsCount", + "success" + ] + }, + "SchedulesAddRecipientsBody": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "format": "email" }, - "required": [ - "name" - ] - }, - "exportVersion": { - "type": "string", - "enum": [ - "0.1" + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of email addresses to add as recipients.", + "example": [ + "user@example.com" ] }, - "fileUploads": { - "type": "object", - "additionalProperties": {} - }, - "folderPath": { - "type": "string" + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to add as recipients.", + "example": [ + "123e4567-e89b-12d3-a456-426614174000" + ] }, - "identifier": { - "type": "string" + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user UUIDs to add as recipients. Use the List users and List embed users endpoints to retrieve user IDs.", + "example": [ + "987fcdeb-51a2-43d7-9b56-254415f67890" + ] + } + } + }, + "SchedulesRemoveRecipientsResponse": { + "type": "object", + "properties": { + "removedGroupRecipientsCount": { + "type": "number", + "description": "Number of user group recipients removed.", + "example": 1 }, - "queryModels": { - "type": "object", - "additionalProperties": {} + "removedRecipientsCount": { + "type": "number", + "description": "Number of individual recipients removed.", + "example": 2 }, - "workbookModel": {} + "success": { + "type": "boolean", + "description": "Whether the operation was successful.", + "example": true + } }, "required": [ - "baseModelId", - "document", - "exportVersion", - "queryModels" + "removedGroupRecipientsCount", + "removedRecipientsCount", + "success" ] }, - "UserAttributesListResponse": { + "SchedulesRemoveRecipientsBody": { "type": "object", "properties": { - "records": { + "emails": { "type": "array", "items": { - "type": "object", - "properties": { - "default_value": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - }, - { - "type": "null" - } - ], - "description": "Default value applied when no user-specific value is set. When multiple_values is true, this is an array. Null if no default is configured.", - "example": "us-east" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Human-readable description of the attribute and its purpose", - "example": "User region for row-level security filtering" - }, - "id": { - "type": "string", - "description": "Unique identifier for custom attributes. Empty string for system-defined attributes.", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "label": { - "type": "string", - "description": "Display name shown in the Omni UI", - "example": "Region" - }, - "multiple_values": { - "type": "boolean", - "description": "Whether the attribute accepts an array of values. When true, default_value and user-specific values are arrays.", - "example": false - }, - "name": { - "type": "string", - "description": "Reference name used in model SQL and in embed SSO URL parameters", - "example": "region" - }, - "system": { - "type": "boolean", - "description": "System-defined attributes (e.g. omni_user_id, omni_user_email) are built-in and read-only. Custom attributes have system=false.", - "example": false - }, - "type": { - "type": "string", - "enum": [ - "String", - "Number" - ], - "description": "Data type that determines valid values. String attributes accept text, Number attributes accept numeric values stored as strings for precision.", - "example": "String" - } - }, - "required": [ - "default_value", - "description", - "id", - "label", - "multiple_values", - "name", - "system", - "type" - ] + "type": "string", + "format": "email" }, - "description": "All user attribute definitions in the organization, including both system-defined and custom attributes" + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of recipient email addresses to remove from the scheduled task.", + "example": [ + "user@example.com" + ] + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to remove as recipients.", + "example": [ + "123e4567-e89b-12d3-a456-426614174000" + ] + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of recipient user UUIDs to remove from the scheduled task. Use the List users and List embed users endpoints to retrieve user IDs.", + "example": [ + "987fcdeb-51a2-43d7-9b56-254415f67890" + ] + } + } + }, + "SchedulesTransferOwnershipBody": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the user to transfer schedule ownership to. Use the List users endpoint to retrieve user IDs. The new owner must be a member of the same organization, not be the current owner, and have permission to view the dashboard associated with the schedule.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" } }, "required": [ - "records" + "userId" ] }, - "UploadsListResponse": { + "ScimUsersListResponse": { "type": "object", "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + "Resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScimUserResponse" + }, + "description": "List of SCIM users" }, - "records": { + "itemsPerPage": { + "type": "number", + "description": "Items per page" + }, + "schemas": { "type": "array", "items": { - "$ref": "#/components/schemas/Upload" - } + "type": "string" + }, + "description": "SCIM schema URIs" + }, + "startIndex": { + "type": "number", + "description": "Start index (1-based)" + }, + "totalResults": { + "type": "number", + "description": "Total number of results" } }, "required": [ - "pageInfo", - "records" + "Resources", + "itemsPerPage", + "schemas", + "startIndex", + "totalResults" ] }, - "Upload": { + "ScimUserResponse": { "type": "object", "properties": { - "connection_id": { - "type": "string", - "format": "uuid", - "description": "Connection ID the upload is associated with" - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "When the file was uploaded" + "active": { + "type": "boolean", + "description": "Whether the user is active" }, - "file_name": { + "displayName": { "type": "string", - "description": "Original file name", - "example": "users.csv" + "description": "Display name" }, "id": { "type": "string", "format": "uuid", - "description": "Unique identifier for the upload" - }, - "in_db_as_table_name": { - "type": [ - "string", - "null" - ], - "description": "Database table name if uploaded to database scratch schema" - }, - "model_id": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" - }, - "size_bytes": { - "type": [ - "number", - "null" - ], - "description": "File size in bytes" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "Last update timestamp" + "description": "SCIM user ID" }, - "uploaded_by_user": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "User ID of the uploader" - }, - "name": { - "type": "string", - "description": "Name of the user who uploaded the file" - } + "schemas": { + "type": "array", + "items": { + "type": "string" }, - "required": [ - "id", - "name" - ], - "description": "User who uploaded the file" + "description": "SCIM schema URIs" }, - "view_name": { + "userName": { "type": "string", - "description": "View name associated with the upload" + "format": "email", + "description": "Username (email)" } }, "required": [ - "connection_id", - "created_at", - "file_name", + "active", + "displayName", "id", - "in_db_as_table_name", - "model_id", - "size_bytes", - "updated_at", - "uploaded_by_user", - "view_name" + "schemas", + "userName" ] }, - "UploadCreateResponse": { + "ScimUserCreateRequest": { "type": "object", "properties": { - "fileName": { - "type": "string", - "description": "Original file name", - "example": "users.csv" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the upload" - }, - "inDbAsTableName": { - "type": "string", - "description": "Database table name in the scratch schema" - }, - "modelId": { + "displayName": { "type": "string", - "format": "uuid", - "description": "Model ID the view was created in" - }, - "rowCount": { - "type": "integer", - "description": "Number of rows in the uploaded file" - }, - "truncated": { - "type": "boolean", - "description": "Whether the file was truncated due to row limit" + "description": "Display name of the user", + "example": "John Doe" }, - "viewCreated": { - "type": "boolean", - "description": "Whether a view was created in the model" + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Omni user attributes" }, - "viewName": { + "userName": { "type": "string", - "description": "Name of the view created" + "format": "email", + "description": "Email address (username) of the user", + "example": "user@example.com" } }, "required": [ - "fileName", - "id", - "inDbAsTableName", - "modelId", - "rowCount", - "truncated", - "viewCreated", - "viewName" + "displayName", + "userName" ] }, - "UploadCreateBody": { + "ScimUserPutRequest": { "type": "object", "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" + "active": { + "type": "boolean", + "default": true, + "description": "Whether the user is active" }, - "branchName": { + "displayName": { "type": "string", - "description": "Name of the branch to create the view in (mutually exclusive with branchId)" + "description": "Display name of the user" }, - "file": { - "type": "string", - "description": "The CSV file to upload", - "format": "binary" + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Enterprise SCIM user attributes" }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "UUID of the model to create the view in" + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Omni user attributes" }, - "viewName": { + "userName": { "type": "string", - "description": "Override the view name (defaults to sanitized file name)" + "format": "email", + "description": "Email address (username) of the user", + "example": "user@example.com" } }, "required": [ - "file", - "modelId" + "userName" ] }, - "UploadDeleteResponse": { + "ScimUserPatchRequest": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the deletion was successful" + "Operations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace", + "add", + "Add", + "Remove", + "remove" + ] + }, + "path": { + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "active": { + "type": "boolean" + }, + "displayName": { + "type": "string" + }, + "userName": { + "type": "string", + "format": "email" + } + } + } + ] + } + }, + "required": [ + "op", + "value" + ] + }, + "minItems": 1, + "description": "List of patch operations to apply" + }, + "schemas": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "urn:ietf:params:scim:api:messages:2.0:PatchOp" + ] + }, + "description": "SCIM schema URIs" } }, "required": [ - "success" + "Operations", + "schemas" ] }, - "UsersGetModelRolesResponse": { + "ScimGroupsListResponse": { "type": "object", "properties": { - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" + "Resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScimGroupResponse" + }, + "description": "List of SCIM groups" }, - "results": { + "itemsPerPage": { + "type": "number", + "description": "Items per page" + }, + "schemas": { "type": "array", "items": { - "$ref": "#/components/schemas/RoleAssignmentResult" + "type": "string" }, - "description": "List of role assignments" + "description": "SCIM schema URIs" + }, + "startIndex": { + "type": "number", + "description": "Start index (1-based)" + }, + "totalResults": { + "type": "number", + "description": "Total number of results" } }, "required": [ - "membershipId", - "results" + "Resources", + "itemsPerPage", + "schemas", + "startIndex", + "totalResults" ] }, - "RoleAssignmentResult": { + "ScimGroupResponse": { "type": "object", "properties": { - "baseRole": { - "type": "string", - "description": "The base role definition name", - "example": "VIEWER" - }, - "connectionId": { + "displayName": { "type": "string", - "format": "uuid", - "description": "Connection this role applies to" - }, - "from": { - "$ref": "#/components/schemas/RoleOrigin" + "description": "Group display name" }, - "modelId": { + "id": { "type": "string", - "format": "uuid", - "description": "Model this role applies to" - }, - "priority": { - "type": "number", - "description": "Priority for role resolution (higher = more permissive)" + "description": "SCIM group ID (miniUuid)" }, - "resolved": { - "type": "boolean", - "description": "Whether this is the resolved (effective) role" + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Member display name" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "Member user ID" + } + }, + "required": [ + "display", + "value" + ] + }, + "description": "Group members" }, - "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" } }, "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "resolved", - "roleName" - ] - }, - "RoleOrigin": { - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "USER" - ], - "description": "Role assigned directly to user" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "ORG" - ], - "description": "Role inherited from organization" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "BASE" - ], - "description": "Connection base role" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { - "type": "string", - "description": "Name of the group", - "example": "Engineering Team" - }, - "type": { - "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role inherited from group membership" - } - }, - "required": [ - "depth", - "miniUuid", - "name", - "type" - ] - } - ], - "description": "Origin of this role assignment" - }, - "UsersAssignModelRoleResponse": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "The connection ID for this role assignment" - }, - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The model ID for this role assignment" - }, - "roleName": { - "type": "string", - "description": "The assigned role name", - "example": "VIEWER" - } - }, - "required": [ - "connectionId", - "membershipId", - "modelId", - "roleName" + "displayName", + "id", + "schemas" ] }, - "UsersAssignModelRoleBody": { + "ScimGroupsCreateBody": { "type": "object", "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model ID for model-level role assignment. Required if connectionId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "roleName": { + "displayName": { "type": "string", - "minLength": 1, - "description": "Name of the role to assign (base or custom role)", - "example": "VIEWER" - } - }, - "required": [ - "roleName" - ] - }, - "UsersListEmailOnlyResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + "description": "Display name of the group", + "example": "Engineering Team" }, - "records": { + "members": { "type": "array", "items": { "type": "object", "properties": { - "email": { - "type": "string", - "description": "User email address", - "example": "user@example.com" - }, - "user_attributes": { - "type": "object", - "additionalProperties": {}, - "description": "User attributes as key-value pairs" - }, - "user_id": { + "value": { "type": "string", "format": "uuid", - "description": "User ID" + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" } }, "required": [ - "email", - "user_attributes", - "user_id" + "value" ] - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "UsersCreateEmailOnlyResponse": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "ID of the created user" + }, + "default": [], + "description": "List of group members" } }, "required": [ - "email", - "userId" + "displayName" ] }, - "UsersCreateEmailOnlyBody": { + "ScimGroupsReplaceBody": { "type": "object", "properties": { - "email": { + "displayName": { "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" + "description": "Display name of the group", + "example": "Engineering Team" }, - "userAttributes": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "Optional user attributes as key-value pairs" - } - }, - "required": [ - "email" - ] - }, - "UsersCreateEmailOnlyBulkResponse": { - "type": "object", - "properties": { - "results": { + "members": { "type": "array", "items": { "type": "object", "properties": { - "email": { + "display": { "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" + "description": "Display name of the member", + "example": "john.doe@example.com" }, - "userId": { + "value": { "type": "string", "format": "uuid", - "description": "ID of the created user" + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" } }, "required": [ - "email", - "userId" + "display", + "value" ] }, - "description": "Results for each created user" + "description": "List of group members" } }, "required": [ - "results" + "displayName", + "members" ] }, - "UsersCreateEmailOnlyBulkBody": { + "ScimGroupsPatchBody": { "type": "object", "properties": { - "users": { + "Operations": { "type": "array", "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" - }, - "userAttributes": { + "anyOf": [ + { "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace" + ], + "description": "Operation type", + "example": "replace" + }, + "value": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "New display name", + "example": "Engineering Team" + }, + "id": { + "type": "string", + "description": "Group ID" + } }, - { - "type": "null" + "required": [ + "displayName" + ] + } + }, + "required": [ + "op", + "value" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "remove", + "Remove" + ], + "description": "Operation type", + "example": "remove" + }, + "path": { + "type": "string", + "pattern": "members\\[value eq \"(.{36})\"\\]", + "description": "SCIM path for member to remove", + "example": "members[value eq \"550e8400-e29b-41d4-a716-446655440000\"]" + } + }, + "required": [ + "op", + "path" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "add", + "Add" + ], + "description": "Operation type", + "example": "add" + }, + "path": { + "type": "string", + "enum": [ + "members" + ], + "description": "Path for members", + "example": "members" + }, + "value": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] } - ] + } }, - "description": "Optional user attributes as key-value pairs" + "required": [ + "op", + "path", + "value" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace" + ], + "description": "Operation type", + "example": "replace" + }, + "path": { + "type": "string", + "enum": [ + "members", + "displayName" + ], + "description": "Path for attribute to replace", + "example": "members" + }, + "value": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] + } + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "op", + "path", + "value" + ] } - }, - "required": [ - "email" ] }, - "minItems": 1, - "maxItems": 20, - "description": "Array of users to create (1-20 users)" - } - }, - "required": [ - "users" - ] - }, - "UserGroupsGetModelRolesResponse": { - "type": "object", - "properties": { - "results": { + "description": "List of SCIM patch operations" + }, + "schemas": { "type": "array", "items": { - "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" + "type": "string", + "enum": [ + "urn:ietf:params:scim:api:messages:2.0:PatchOp" + ] }, - "description": "List of role assignments" - }, - "userGroupId": { - "type": "string", - "description": "The user group short identifier", - "example": "abc123" + "description": "SCIM schema URIs" } }, "required": [ - "results", - "userGroupId" + "Operations", + "schemas" ] }, - "UserGroupRoleAssignmentResult": { + "DocumentExportResponse": { "type": "object", "properties": { - "baseRole": { - "type": "string", - "description": "The base role definition name", - "example": "VIEWER" + "dashboard": { + "description": "Dashboard configuration and layout" }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection this role applies to" + "document": { + "type": "object", + "properties": { + "ephemeral": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] }, - "from": { - "$ref": "#/components/schemas/UserGroupRoleOrigin" + "exportVersion": { + "type": "string" }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model this role applies to" + "fileUploads": { + "type": "object", + "additionalProperties": {} }, - "priority": { - "type": "number", - "description": "Priority for role resolution (higher = more permissive)" + "queryModels": { + "type": "object", + "additionalProperties": {} }, - "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" - } + "workbookModel": {} }, "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "roleName" + "document", + "exportVersion", + "queryModels" ] }, - "UserGroupRoleOrigin": { + "DocumentImportResponse": { "type": "object", "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group (0 for direct assignment)" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { + "documentId": { "type": "string", - "description": "Name of the group", - "example": "Engineering Team" + "format": "uuid", + "description": "ID of the imported document" }, - "type": { + "identifier": { "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role assigned to group" + "description": "Document identifier (miniUuid)" } }, "required": [ - "depth", - "miniUuid", - "name", - "type" - ], - "description": "Origin of this role assignment" + "documentId", + "identifier" + ] }, - "UserGroupsAssignModelRoleResponse": { + "DocumentImportBody": { "type": "object", "properties": { - "connectionId": { + "baseModelId": { "type": "string", "format": "uuid", - "description": "The connection ID for this role assignment" + "description": "Base model ID for the imported document" }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The model ID for this role assignment" + "dashboard": { + "description": "Dashboard export data" }, - "roleName": { - "type": "string", - "description": "The assigned role name", - "example": "VIEWER" + "document": { + "type": "object", + "properties": { + "ephemeral": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] }, - "userGroupId": { + "exportVersion": { "type": "string", - "description": "The user group short identifier", - "example": "abc123" + "enum": [ + "0.1" + ] + }, + "fileUploads": { + "type": "object", + "additionalProperties": {} + }, + "folderPath": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "queryModels": { + "type": "object", + "additionalProperties": {} + }, + "workbookModel": {} + }, + "required": [ + "baseModelId", + "document", + "exportVersion", + "queryModels" + ] + }, + "UserAttributesListResponse": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "default_value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + { + "type": "null" + } + ], + "description": "Default value applied when no user-specific value is set. When multiple_values is true, this is an array. Null if no default is configured.", + "example": "us-east" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Human-readable description of the attribute and its purpose", + "example": "User region for row-level security filtering" + }, + "id": { + "type": "string", + "description": "Unique identifier for custom attributes. Empty string for system-defined attributes.", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "label": { + "type": "string", + "description": "Display name shown in the Omni UI", + "example": "Region" + }, + "multiple_values": { + "type": "boolean", + "description": "Whether the attribute accepts an array of values. When true, default_value and user-specific values are arrays.", + "example": false + }, + "name": { + "type": "string", + "description": "Reference name used in model SQL and in embed SSO URL parameters", + "example": "region" + }, + "system": { + "type": "boolean", + "description": "System-defined attributes (e.g. omni_user_id, omni_user_email) are built-in and read-only. Custom attributes have system=false.", + "example": false + }, + "type": { + "type": "string", + "enum": [ + "String", + "Number" + ], + "description": "Data type that determines valid values. String attributes accept text, Number attributes accept numeric values stored as strings for precision.", + "example": "String" + } + }, + "required": [ + "default_value", + "description", + "id", + "label", + "multiple_values", + "name", + "system", + "type" + ] + }, + "description": "All user attribute definitions in the organization, including both system-defined and custom attributes" } }, "required": [ - "connectionId", - "modelId", - "roleName", - "userGroupId" + "records" ] }, - "UserGroupsAssignModelRoleBody": { + "UploadsListResponse": { "type": "object", "properties": { - "connectionId": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Upload" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Upload": { + "type": "object", + "properties": { + "connection_id": { "type": "string", "format": "uuid", - "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection ID the upload is associated with" }, - "modelId": { + "created_at": { "type": "string", - "format": "uuid", - "description": "Model ID for model-level role assignment. Required if connectionId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "format": "date-time", + "description": "When the file was uploaded" }, - "roleName": { + "file_name": { "type": "string", - "minLength": 1, - "description": "Name of the role to assign (base or custom role)", - "example": "VIEWER" - } - }, - "required": [ - "roleName" - ] - } - }, - "parameters": {} - }, - "paths": { - "/api/v1/ai/generate-query": { - "post": { - "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", - "operationId": "aiGenerateQuery", - "summary": "Generate query from natural language", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiGenerateQueryBody" - } - } - } - }, - "responses": { - "200": { - "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiGenerateQueryResponse" - } - } - } + "description": "Original file name", + "example": "users.csv" }, - "400": { - "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "in_db_as_table_name": { + "type": [ + "string", + "null" + ], + "description": "Database table name if uploaded to database scratch schema" }, - "402": { - "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiCreditShutoffError" - } - } - } + "model_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" }, - "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "size_bytes": { + "type": [ + "number", + "null" + ], + "description": "File size in bytes" }, - "404": { - "description": "The specified model or topic was not found in the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" }, - "500": { - "description": "AI service error." - } - } - } - }, - "/api/v1/ai/pick-topic": { - "post": { - "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", - "operationId": "aiPickTopic", - "summary": "Pick the best topic for a prompt", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiPickTopicBody" + "uploaded_by_user": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "User ID of the uploader" + }, + "name": { + "type": "string", + "description": "Name of the user who uploaded the file" } - } + }, + "required": [ + "id", + "name" + ], + "description": "User who uploaded the file" + }, + "view_name": { + "type": "string", + "description": "View name associated with the upload" } }, - "responses": { - "200": { - "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiPickTopicResponse" - } - } - } + "required": [ + "connection_id", + "created_at", + "file_name", + "id", + "in_db_as_table_name", + "model_id", + "size_bytes", + "updated_at", + "uploaded_by_user", + "view_name" + ] + }, + "UploadCreateResponse": { + "type": "object", + "properties": { + "fileName": { + "type": "string", + "description": "Original file name", + "example": "users.csv" }, - "400": { - "description": "Invalid request body. The prompt or modelId may be missing or malformed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "inDbAsTableName": { + "type": "string", + "description": "Database table name in the scratch schema" }, - "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID the view was created in" }, - "404": { - "description": "The specified model was not found, or no accessible topics exist in the model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "rowCount": { + "type": "integer", + "description": "Number of rows in the uploaded file" }, - "500": { - "description": "AI service error." - } - } - } - }, - "/api/v1/ai/search-omni-docs": { - "post": { - "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", - "operationId": "aiSearchOmniDocs", - "summary": "Search Omni documentation", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsBody" - } - } + "truncated": { + "type": "boolean", + "description": "Whether the file was truncated due to row limit" + }, + "viewCreated": { + "type": "boolean", + "description": "Whether a view was created in the model" + }, + "viewName": { + "type": "string", + "description": "Name of the view created" } }, - "responses": { - "200": { - "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsResponse" - } - } - } + "required": [ + "fileName", + "id", + "inDbAsTableName", + "modelId", + "rowCount", + "truncated", + "viewCreated", + "viewName" + ] + }, + "UploadCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" }, - "400": { - "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "branchName": { + "type": "string", + "description": "Name of the branch to create the view in (mutually exclusive with branchId)" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "file": { + "type": "string", + "description": "The CSV file to upload", + "format": "binary" }, - "403": { - "description": "Omni Agent is not enabled for this organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "UUID of the model to create the view in" }, - "500": { - "description": "AI service error." + "viewName": { + "type": "string", + "description": "Override the view name (defaults to sanitized file name)" } - } - } - }, - "/api/v1/ai/jobs": { - "post": { - "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", - "operationId": "aiJobSubmit", - "summary": "Submit an AI job", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + }, + "required": [ + "file", + "modelId" + ] + }, + "UploadDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the deletion was successful" } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitBody" - } - } + }, + "required": [ + "success" + ] + }, + "UsersGetModelRolesResponse": { + "type": "object", + "properties": { + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoleAssignmentResult" + }, + "description": "List of role assignments" } }, - "responses": { - "201": { - "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitResponse" - } - } - } + "required": [ + "membershipId", + "results" + ] + }, + "RoleAssignmentResult": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The base role definition name", + "example": "VIEWER" }, - "400": { - "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection this role applies to" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "from": { + "$ref": "#/components/schemas/RoleOrigin" }, - "403": { - "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model this role applies to" }, - "404": { - "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" }, - "409": { - "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } + "resolved": { + "type": "boolean", + "description": "Whether this is the resolved (effective) role" + }, + "roleName": { + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" } - } - } - }, - "/api/v1/ai/jobs/{jobId}": { - "get": { - "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", - "operationId": "aiJobStatus", - "summary": "Get AI job status", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobStatusResponse" - } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "resolved", + "roleName" + ] + }, + "RoleOrigin": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "USER" + ], + "description": "Role assigned directly to user" } - } + }, + "required": [ + "type" + ] }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ORG" + ], + "description": "Role inherited from organization" } - } + }, + "required": [ + "type" + ] }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "BASE" + ], + "description": "Connection base role" } - } + }, + "required": [ + "type" + ] }, - "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - } - }, - "/api/v1/ai/jobs/{jobId}/cancel": { - "post": { - "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", - "operationId": "aiJobCancel", - "summary": "Cancel an AI job", - "tags": [ - "AI" - ], - "parameters": [ { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role inherited from group membership" + } }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" + "required": [ + "depth", + "miniUuid", + "name", + "type" + ] } ], - "responses": { - "200": { - "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobCancelResponse" - } - } - } + "description": "Origin of this role assignment" + }, + "UsersAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" }, - "403": { - "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + } + }, + "required": [ + "connectionId", + "membershipId", + "modelId", + "roleName" + ] + }, + "UsersAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "409": { - "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" } - } - } - }, - "/api/v1/ai/jobs/{jobId}/result": { - "get": { - "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", - "operationId": "aiJobResult", - "summary": "Get AI job result", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { + }, + "required": [ + "roleName" + ] + }, + "UsersListEmailOnlyResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "User email address", + "example": "user@example.com" + }, + "user_attributes": { + "type": "object", + "additionalProperties": {}, + "description": "User attributes as key-value pairs" + }, + "user_id": { + "type": "string", + "format": "uuid", + "description": "User ID" + } + }, + "required": [ + "email", + "user_attributes", + "user_id" + ] + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "UsersCreateEmailOnlyResponse": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "UsersCreateEmailOnlyBody": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "UsersCreateEmailOnlyBulkResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "description": "Results for each created user" + } + }, + "required": [ + "results" + ] + }, + "UsersCreateEmailOnlyBulkBody": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "minItems": 1, + "maxItems": 20, + "description": "Array of users to create (1-20 users)" + } + }, + "required": [ + "users" + ] + }, + "UserGroupsGetModelRolesResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" + }, + "description": "List of role assignments" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" + } + }, + "required": [ + "results", + "userGroupId" + ] + }, + "UserGroupRoleAssignmentResult": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The base role definition name", + "example": "VIEWER" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection this role applies to" + }, + "from": { + "$ref": "#/components/schemas/UserGroupRoleOrigin" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model this role applies to" + }, + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" + }, + "roleName": { + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "roleName" + ] + }, + "UserGroupRoleOrigin": { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group (0 for direct assignment)" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role assigned to group" + } + }, + "required": [ + "depth", + "miniUuid", + "name", + "type" + ], + "description": "Origin of this role assignment" + }, + "UserGroupsAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" + }, + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" + } + }, + "required": [ + "connectionId", + "modelId", + "roleName", + "userGroupId" + ] + }, + "UserGroupsAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" + } + }, + "required": [ + "roleName" + ] + } + }, + "parameters": {} + }, + "paths": { + "/api/v1/ai/generate-query": { + "post": { + "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", + "operationId": "aiGenerateQuery", + "summary": "Generate query from natural language", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "402": { + "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditShutoffError" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model or topic was not found in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/pick-topic": { + "post": { + "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", + "operationId": "aiPickTopic", + "summary": "Pick the best topic for a prompt", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicBody" + } + } + } + }, + "responses": { + "200": { + "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. The prompt or modelId may be missing or malformed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model was not found, or no accessible topics exist in the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/search-omni-docs": { + "post": { + "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", + "operationId": "aiSearchOmniDocs", + "summary": "Search Omni documentation", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Omni Agent is not enabled for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/jobs": { + "post": { + "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", + "operationId": "aiJobSubmit", + "summary": "Submit an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitBody" + } + } + } + }, + "responses": { + "201": { + "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}": { + "get": { + "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", + "operationId": "aiJobStatus", + "summary": "Get AI job status", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobStatusResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/cancel": { + "post": { + "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", + "operationId": "aiJobCancel", + "summary": "Cancel an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobCancelResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/result": { + "get": { + "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", + "operationId": "aiJobResult", + "summary": "Get AI job result", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobResultResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "404": { + "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/vis": { + "get": { + "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", + "operationId": "aiJobVisualization", + "summary": "Render AI job visualization", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "content": { + "image/png": { + "schema": { + "format": "binary", + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "404": { + "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "422": { + "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError422" + } + } + } + } + } + } + }, + "/api/v1/ai/branding": { + "get": { + "description": "Returns the organization's AI helper branding — display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", + "operationId": "aiBranding", + "summary": "Get AI helper branding", + "tags": [ + "AI" + ], + "responses": { + "200": { + "description": "AI branding retrieved successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiBrandingResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations": { + "get": { + "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next page.", + "operationId": "aiConversationsList", + "summary": "List AI conversations", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of conversations.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiConversationsListResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations/{conversationId}": { + "get": { + "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", + "operationId": "aiConversationDetail", + "summary": "Get AI conversation with messages", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "format": "uuid" }, "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", + "name": "conversationId", "in": "path" } ], "responses": { "200": { - "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", + "description": "Conversation with messages in chronological order.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiJobResultResponse" + "$ref": "#/components/schemas/AiConversationDetailResponse" } } } }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", + "401": { + "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError400" + "$ref": "#/components/schemas/ApiError401" } } } }, - "401": { - "description": "Missing or invalid API key.", + "403": { + "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError401" + "$ref": "#/components/schemas/ApiError403" } } } }, "404": { - "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", + "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user — existence of another user's conversations is not disclosed.", "content": { "application/json": { "schema": { @@ -30396,525 +31092,1115 @@ } } }, - "/api/v1/ai/jobs/{jobId}/vis": { + "/api/v1/api-keys": { "get": { - "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", - "operationId": "aiJobVisualization", - "summary": "Render AI job visualization", + "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", + "operationId": "apiKeysList", + "summary": "List API tokens", "tags": [ - "AI" + "API Tokens" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Cursor from the previous response (token UUID)" }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" + "required": false, + "description": "Cursor from the previous response (token UUID)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "createdAt", + "name" + ], + "default": "createdAt" + }, + "required": false, + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Filter by API token type. When omitted, all types are returned.", + "example": "personal" + }, + "required": false, + "description": "Filter by API token type. When omitted, all types are returned.", + "name": "type", + "in": "query" } ], "responses": { "200": { - "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "description": "Paginated list of API tokens", "content": { - "image/png": { + "application/json": { "schema": { - "format": "binary", - "type": "string" + "$ref": "#/components/schemas/ApiKeyListResponse" } } } }, "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "description": "Invalid query parameters" }, "401": { - "description": "Missing or invalid API key.", + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + } + } + } + }, + "/api/v1/api-keys/{id}": { + "get": { + "description": "Returns a single API token by id. Requires organization admin permissions.", + "operationId": "apiKeysGet", + "summary": "Get API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The requested API token", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError401" + "$ref": "#/components/schemas/ApiKey" } } } }, + "400": { + "description": "Malformed `id` (must be a UUID)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + }, "404": { - "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } + "description": "Token not found in this organization" + } + } + }, + "put": { + "description": "Enables or disables an API token. Requires organization admin permissions.", + "operationId": "apiKeysUpdate", + "summary": "Enable or disable an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyUpdateBody" } } - }, - "422": { - "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", + } + }, + "responses": { + "200": { + "description": "The updated API token", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError422" + "$ref": "#/components/schemas/ApiKey" } } } + }, + "400": { + "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + }, + "delete": { + "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", + "operationId": "apiKeysDelete", + "summary": "Revoke an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" } - } - } - }, - "/api/v1/ai/branding": { - "get": { - "description": "Returns the organization's AI helper branding — display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", - "operationId": "aiBranding", - "summary": "Get AI helper branding", - "tags": [ - "AI" ], "responses": { "200": { - "description": "AI branding retrieved successfully.", + "description": "The token was revoked", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiBrandingResponse" + "$ref": "#/components/schemas/ApiKeyDeleteResponse" } } } }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "400": { + "description": "Malformed `id`, or missing/malformed `Authorization` header" }, "403": { - "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" } } } }, - "/api/v1/ai/conversations": { + "/api/v1/connections": { "get": { - "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next page.", - "operationId": "aiConversationsList", - "summary": "List AI conversations", + "operationId": "connectionsList", + "summary": "List connections", "tags": [ - "AI" + "Connections" ], "parameters": [ { "schema": { "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" + "description": "Filter by database name (case-insensitive contains)", + "example": "analytics" }, "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", + "description": "Filter by database name (case-insensitive contains)", + "name": "database", "in": "query" }, { "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 + "type": "string", + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "example": "snowflake,bigquery" }, "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "name": "dialect", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "description": "Include soft-deleted connections in results", + "example": false + }, + "required": false, + "description": "Include soft-deleted connections in results", + "name": "includeDeleted", "in": "query" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Filter by connection name (case-insensitive contains)", + "example": "Production" }, "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", + "description": "Filter by connection name (case-insensitive contains)", + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "desc" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "database", + "dialect", + "name" + ], + "description": "Field to sort by", + "example": "name" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", "in": "query" } ], "responses": { "200": { - "description": "Paginated list of conversations.", + "description": "List of connections", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiConversationsListResponse" + "type": "object", + "properties": { + "connections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "description": "Whether branch environments override user attributes", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + }, + "description": "List of connections" + } + }, + "required": [ + "connections" + ], + "description": "List connections response", + "title": "ConnectionsListResponse" } } } }, "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "description": "Authentication required" }, "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "description": "Permission denied - admin role required" } } - } - }, - "/api/v1/ai/conversations/{conversationId}": { - "get": { - "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", - "operationId": "aiConversationDetail", - "summary": "Get AI conversation with messages", + }, + "post": { + "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", + "operationId": "connectionsCreate", + "summary": "Create connection", "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid" - }, - "required": true, - "name": "conversationId", - "in": "path" - } + "Connections" ], - "responses": { - "200": { - "description": "Conversation with messages in chronological order.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiConversationDetailResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user — existence of another user's conversations is not disclosed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "acceptsLicense": { + "type": "boolean", + "description": "Acceptance of the license terms. Required for Oracle connections.", + "example": true + }, + "allowsUserSpecificTimezones": { + "type": "boolean", + "default": false, + "description": "Whether to allow users to specify their own timezones", + "example": false + }, + "alwaysScopeViewNames": { + "type": "boolean", + "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", + "example": true + }, + "authenticationType": { + "type": "string", + "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", + "example": "snowflake-password" + }, + "awsRoleArn": { + "type": "string", + "description": "AWS IAM role ARN. Applicable for Athena only.", + "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" + }, + "baseRole": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "RESTRICTED_QUERIER", + "QUERIER", + "MODELER", + "CONNECTION_ADMIN" + ], + "description": "The default role for users accessing the connection", + "example": "QUERIER" + }, + "database": { + "type": "string", + "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", + "example": "analytics_db" + }, + "defaultSchema": { + "type": "string", + "description": "The default schema to use. Required for MSSQL.", + "example": "public" + }, + "dialect": { + "type": "string", + "enum": [ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "exasol", + "mariadb", + "motherduck", + "mssql", + "mysql", + "oracle", + "postgres", + "redshift", + "sap_hana", + "snowflake", + "starrocks", + "trino" + ], + "description": "The database dialect", + "example": "snowflake" + }, + "enableDbSemanticLayerIntegration": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", + "example": false + }, + "enableDbSemanticLayerTopics": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", + "example": false + }, + "externalOauthAudience": { + "type": "string", + "description": "External OAuth audience claim. Applicable for Snowflake." + }, + "externalOauthAuthorizationUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/authorize" + }, + "externalOauthTokenUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/token" + }, + "host": { + "type": "string", + "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", + "example": "myaccount" + }, + "hostOverride": { + "type": "string", + "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", + "example": "myaccount.snowflakecomputing.com" + }, + "includeOtherCatalogs": { + "type": "string", + "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", + "example": "other_project1,other_project2" + }, + "includeSchemas": { + "type": "string", + "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", + "example": "public,analytics" + }, + "inferRelationshipsFromColumnNames": { + "type": "boolean", + "default": true, + "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", + "example": true + }, + "inferRelationshipsFromForeignKeys": { + "type": "boolean", + "default": false, + "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "example": false + }, + "maxBillingBytes": { + "type": "string", + "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", + "example": "1000000000" + }, + "name": { + "type": "string", + "description": "A descriptive name for the connection", + "example": "Production Warehouse" + }, + "oauthClientId": { + "type": "string", + "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "oauthClientSecretUnencrypted": { + "type": "string", + "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "offloadedSchemas": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", + "example": [ + "analytics_archive" + ] + }, + "passwordUnencrypted": { + "type": "string", + "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." + }, + "port": { + "type": "integer", + "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", + "example": 5432 + }, + "privateKey": { + "type": "string", + "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." + }, + "queryTimeoutSeconds": { + "type": "integer", + "maximum": 3600, + "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", + "example": 900 + }, + "queryTimezone": { + "type": "string", + "description": "The timezone to use for queries", + "example": "NONE" + }, + "region": { + "type": "string", + "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", + "example": "us-east-1" + }, + "scratchSchema": { + "type": "string", + "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", + "example": "omni_scratch" + }, + "systemTimezone": { + "type": "string", + "description": "The timezone to use for the system", + "example": "UTC" + }, + "trustServerCertificate": { + "type": "boolean", + "default": false, + "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", + "example": false + }, + "useMachineAuth": { + "type": "boolean", + "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "example": false + }, + "username": { + "type": "string", + "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", + "example": "analytics_user" + }, + "warehouse": { + "type": "string", + "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path).", + "example": "COMPUTE_WH" + } + }, + "required": [ + "dialect", + "name", + "passwordUnencrypted" + ], + "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", + "title": "ConnectionsCreateBody" } } } - } - } - }, - "/api/v1/api-keys": { - "get": { - "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", - "operationId": "apiKeysList", - "summary": "List API tokens", - "tags": [ - "API Tokens" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Cursor from the previous response (token UUID)" - }, - "required": false, - "description": "Cursor from the previous response (token UUID)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "createdAt", - "name" - ], - "default": "createdAt" - }, - "required": false, - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "personal", - "mcp" - ], - "description": "Filter by API token type. When omitted, all types are returned.", - "example": "personal" - }, - "required": false, - "description": "Filter by API token type. When omitted, all types are returned.", - "name": "type", - "in": "query" - } - ], + }, "responses": { - "200": { - "description": "Paginated list of API tokens", + "201": { + "description": "Connection created successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyListResponse" + "type": "object", + "properties": { + "data": { + "type": "string", + "format": "uuid", + "description": "Created connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "data", + "success" + ], + "description": "Create connection response", + "title": "ConnectionsCreateResponse" } } } }, "400": { - "description": "Invalid query parameters" + "description": "Invalid request body or dialect" }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions" + "description": "Permission denied - admin role required" } } } }, - "/api/v1/api-keys/{id}": { + "/api/v1/connections/{id}": { "get": { - "description": "Returns a single API token by id. Requires organization admin permissions.", - "operationId": "apiKeysGet", - "summary": "Get API token", - "tags": [ - "API Tokens" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "Token UUID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "The requested API token", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKey" - } - } - } - }, - "400": { - "description": "Malformed `id` (must be a UUID)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Insufficient permissions" - }, - "404": { - "description": "Token not found in this organization" - } - } - }, - "put": { - "description": "Enables or disables an API token. Requires organization admin permissions.", - "operationId": "apiKeysUpdate", - "summary": "Enable or disable an API token", + "description": "Fetch a single connection by ID.", + "operationId": "connectionsGet", + "summary": "Get connection", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", + "description": "Connection ID", "name": "id", "in": "path" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKeyUpdateBody" - } - } - } - }, "responses": { "200": { - "description": "The updated API token", + "description": "Connection object", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKey" + "type": "object", + "properties": { + "connection": { + "type": "object", + "properties": { + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "description": "Whether branch environments override user attributes", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + } + }, + "required": [ + "connection" + ], + "description": "Get connection response", + "title": "ConnectionsGetResponse" } } } }, - "400": { - "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" + "401": { + "description": "Authentication required" }, "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" + "description": "Permission denied — caller lacks READ on the connection" }, "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" + "description": "Connection does not exist" } } }, - "delete": { - "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", - "operationId": "apiKeysDelete", - "summary": "Revoke an API token", + "patch": { + "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", + "operationId": "connectionsUpdate", + "summary": "Update connection", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", + "description": "Connection ID", "name": "id", "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "Default role to assign to this connection", + "example": "QUERIER" + }, + "environmentUserAttribute": { + "type": [ + "object", + "null" + ], + "properties": { + "attributeName": { + "type": "string", + "description": "Name of the user attribute for environment selection", + "example": "region" + }, + "defaultValues": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default values for the user attribute", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "attributeName", + "defaultValues" + ], + "description": "User attribute settings for connection environments" + }, + "passwordUnencrypted": { + "type": "string", + "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." + }, + "privateKey": { + "type": "string", + "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." + } + }, + "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", + "title": "ConnectionsUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "The token was revoked", + "description": "Connection updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyDeleteResponse" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing what was updated", + "example": "Updated connection default role." + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Update connection response", + "title": "ConnectionsUpdateResponse" } } } }, "400": { - "description": "Malformed `id`, or missing/malformed `Authorization` header" + "description": "Invalid request body - at least one field must be provided" + }, + "401": { + "description": "Authentication required" }, "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" + "description": "Connection not found" } } - } - }, - "/api/v1/connections": { - "get": { - "operationId": "connectionsList", - "summary": "List connections", + }, + "delete": { + "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", + "operationId": "connectionsDelete", + "summary": "Delete connection", "tags": [ "Connections" ], @@ -30922,232 +32208,41 @@ { "schema": { "type": "string", - "description": "Filter by database name (case-insensitive contains)", - "example": "analytics" - }, - "required": false, - "description": "Filter by database name (case-insensitive contains)", - "name": "database", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "example": "snowflake,bigquery" - }, - "required": false, - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "name": "dialect", - "in": "query" - }, - { - "schema": { - "type": "boolean", - "description": "Include soft-deleted connections in results", - "example": false - }, - "required": false, - "description": "Include soft-deleted connections in results", - "name": "includeDeleted", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by connection name (case-insensitive contains)", - "example": "Production" - }, - "required": false, - "description": "Filter by connection name (case-insensitive contains)", - "name": "name", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "description": "Sort direction", - "example": "desc" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "database", - "dialect", - "name" - ], - "description": "Field to sort by", - "example": "name" + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" } - ], - "responses": { - "200": { - "description": "List of connections", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseRole": { - "type": [ - "string", - "null" - ], - "description": "Default role for users on this connection", - "example": "QUERIER" - }, - "branchConnectionEnvironmentOverridesUserAttr": { - "type": [ - "boolean", - "null" - ], - "description": "Whether branch environments override user attributes", - "example": false - }, - "createdAt": { - "type": "string", - "description": "Timestamp when connection was created (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "database": { - "type": [ - "string", - "null" - ], - "description": "Database name", - "example": "analytics_db" - }, - "defaultSchema": { - "type": [ - "string", - "null" - ], - "description": "Default schema for the connection", - "example": "public" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when connection was deleted (ISO 8601)", - "example": null - }, - "dialect": { - "type": "string", - "enum": [ - "snowflake", - "bigquery", - "redshift", - "postgres", - "mysql", - "mariadb", - "databricks", - "databricks_lakebase", - "trino", - "athena", - "duckdb", - "motherduck", - "sqlserver", - "clickhouse", - "singlestore" - ], - "description": "Database dialect type", - "example": "snowflake" - }, - "environmentConnectionSwitchesSchemaModel": { - "type": [ - "boolean", - "null" - ], - "description": "Whether environment connections switch schema model", - "example": false - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection identifier", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "name": { - "type": "string", - "description": "Connection display name", - "example": "Production Snowflake" - }, - "updatedAt": { - "type": "string", - "description": "Timestamp when connection was last updated (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "userAttributeNameForConnectionEnvironments": { - "type": [ - "string", - "null" - ], - "description": "User attribute name used for connection environments", - "example": "region" - }, - "userAttributeValuesForDefaultEnvironment": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default user attribute values for the base environment", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "baseRole", - "branchConnectionEnvironmentOverridesUserAttr", - "createdAt", - "database", - "defaultSchema", - "deletedAt", - "dialect", - "environmentConnectionSwitchesSchemaModel", - "id", - "name", - "updatedAt", - "userAttributeNameForConnectionEnvironments", - "userAttributeValuesForDefaultEnvironment" - ], - "description": "Connection object", - "title": "Connection" - }, - "description": "List of connections" + ], + "responses": { + "200": { + "description": "Connection moved to trash", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing the result", + "example": "Connection moved to trash." + }, + "success": { + "type": "boolean", + "description": "True when the connection was archived", + "example": true } }, "required": [ - "connections" + "message", + "success" ], - "description": "List connections response", - "title": "ConnectionsListResponse" + "description": "Archive connection response", + "title": "ConnectionsDeleteResponse" } } } @@ -31156,276 +32251,332 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + }, + "410": { + "description": "Connection has already been archived" } } - }, - "post": { - "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", - "operationId": "connectionsCreate", - "summary": "Create connection", + } + }, + "/api/v1/connections/{connectionId}/dbt": { + "get": { + "operationId": "connectionsDbtGet", + "summary": "Get dbt configuration", "tags": [ "Connections" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "acceptsLicense": { - "type": "boolean", - "description": "Acceptance of the license terms. Required for Oracle connections.", - "example": true - }, - "allowsUserSpecificTimezones": { - "type": "boolean", - "default": false, - "description": "Whether to allow users to specify their own timezones", - "example": false - }, - "alwaysScopeViewNames": { - "type": "boolean", - "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", - "example": true - }, - "authenticationType": { - "type": "string", - "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", - "example": "snowflake-password" - }, - "awsRoleArn": { - "type": "string", - "description": "AWS IAM role ARN. Applicable for Athena only.", - "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" - }, - "baseRole": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "RESTRICTED_QUERIER", - "QUERIER", - "MODELER", - "CONNECTION_ADMIN" - ], - "description": "The default role for users accessing the connection", - "example": "QUERIER" - }, - "database": { - "type": "string", - "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", - "example": "analytics_db" - }, - "defaultSchema": { - "type": "string", - "description": "The default schema to use. Required for MSSQL.", - "example": "public" - }, - "dialect": { - "type": "string", - "enum": [ - "athena", - "bigquery", - "clickhouse", - "databricks", - "databricks_lakebase", - "exasol", - "mariadb", - "motherduck", - "mssql", - "mysql", - "oracle", - "postgres", - "redshift", - "sap_hana", - "snowflake", - "starrocks", - "trino" - ], - "description": "The database dialect", - "example": "snowflake" - }, - "enableDbSemanticLayerIntegration": { - "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", - "example": false - }, - "enableDbSemanticLayerTopics": { + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt configuration for the connection", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Whether relationships are auto-generated from dbt", + "example": true + }, + "branch": { + "type": "string", + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": "string", + "description": "dbt version being used", + "example": "Auto" + }, + "enableSemanticLayer": { + "type": "boolean", + "description": "Whether the dbt semantic layer integration is enabled", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Whether virtual schemas are enabled", + "example": false + }, + "projectRootPath": { + "type": [ + "string", + "null" + ], + "description": "Path to dbt project root", + "example": "dbt_project" + }, + "sshUrl": { + "type": "string", + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + }, + "supportsDbt": { + "type": "boolean", + "enum": [ + true + ], + "description": "Indicates dbt is supported and configured", + "example": true + } + }, + "required": [ + "autogenRelationships", + "branch", + "dbtVersion", + "enableSemanticLayer", + "enableVirtualSchemas", + "projectRootPath", + "sshUrl", + "supportsDbt" + ], + "description": "dbt repository configuration response", + "title": "DbtConfiguredResponse" + }, + { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message explaining dbt status", + "example": "dbt not configured for this connection" + }, + "supportsDbt": { + "type": "boolean", + "description": "Whether the connection dialect supports dbt", + "example": true + } + }, + "required": [ + "message", + "supportsDbt" + ], + "description": "Response when dbt is not configured", + "title": "DbtNotConfiguredResponse" + } + ], + "description": "dbt configuration response", + "title": "ConnectionsDbtGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "put": { + "operationId": "connectionsDbtUpdate", + "summary": "Update dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "autogenRelationships": { "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", - "example": false - }, - "externalOauthAudience": { - "type": "string", - "description": "External OAuth audience claim. Applicable for Snowflake." - }, - "externalOauthAuthorizationUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/authorize" - }, - "externalOauthTokenUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/token" - }, - "host": { - "type": "string", - "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", - "example": "myaccount" - }, - "hostOverride": { - "type": "string", - "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", - "example": "myaccount.snowflakecomputing.com" - }, - "includeOtherCatalogs": { - "type": "string", - "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", - "example": "other_project1,other_project2" + "description": "Automatically generate relationships from dbt", + "example": true }, - "includeSchemas": { + "branch": { "type": "string", - "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", - "example": "public,analytics" + "minLength": 1, + "description": "Git branch name", + "example": "main" }, - "inferRelationshipsFromColumnNames": { - "type": "boolean", - "default": true, - "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", - "example": true + "dbtVersion": { + "type": [ + "string", + "null" + ], + "description": "dbt version to use. Supported: Auto, 1.10, 1.11", + "example": "1.11" }, - "inferRelationshipsFromForeignKeys": { + "enableSemanticLayer": { "type": "boolean", "default": false, - "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "description": "Enable dbt semantic layer integration", "example": false }, - "maxBillingBytes": { - "type": "string", - "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", - "example": "1000000000" - }, - "name": { - "type": "string", - "description": "A descriptive name for the connection", - "example": "Production Warehouse" - }, - "oauthClientId": { - "type": "string", - "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." - }, - "oauthClientSecretUnencrypted": { - "type": "string", - "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." + "enableVirtualSchemas": { + "type": "boolean", + "description": "Enable virtual schemas from dbt", + "example": false }, - "offloadedSchemas": { + "projectRootPath": { "anyOf": [ { - "type": "string" + "type": "string", + "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" }, { - "type": "array", - "items": { - "type": "string" - } + "type": "string", + "enum": [ + "" + ] + }, + { + "type": [ + "object", + "null" + ], + "enum": [ + null + ] + }, + { + "type": "null" } ], - "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", - "example": [ - "analytics_archive" - ] - }, - "passwordUnencrypted": { - "type": "string", - "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." - }, - "port": { - "type": "integer", - "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", - "example": 5432 - }, - "privateKey": { - "type": "string", - "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." - }, - "queryTimeoutSeconds": { - "type": "integer", - "maximum": 3600, - "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", - "example": 900 - }, - "queryTimezone": { - "type": "string", - "description": "The timezone to use for queries", - "example": "NONE" - }, - "region": { - "type": "string", - "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", - "example": "us-east-1" - }, - "scratchSchema": { - "type": "string", - "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", - "example": "omni_scratch" - }, - "systemTimezone": { - "type": "string", - "description": "The timezone to use for the system", - "example": "UTC" + "default": null, + "description": "Path to dbt project root within repository", + "example": "dbt_project" }, - "trustServerCertificate": { + "rotateKeys": { "type": "boolean", "default": false, - "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", - "example": false - }, - "useMachineAuth": { - "type": "boolean", - "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "description": "Rotate SSH deploy keys", "example": false }, - "username": { - "type": "string", - "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", - "example": "analytics_user" - }, - "warehouse": { + "sshUrl": { "type": "string", - "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path).", - "example": "COMPUTE_WH" + "minLength": 1, + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" } }, "required": [ - "dialect", - "name", - "passwordUnencrypted" + "autogenRelationships", + "branch", + "enableVirtualSchemas", + "sshUrl" ], - "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", - "title": "ConnectionsCreateBody" + "description": "dbt repository configuration", + "title": "ConnectionsDbtUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt configuration updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt configuration updated successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt update response", + "title": "ConnectionsDbtUpdateResponse" + } } } + }, + "400": { + "description": "Invalid request body or validation error" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "delete": { + "operationId": "connectionsDbtDelete", + "summary": "Delete dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" } - }, + ], "responses": { - "201": { - "description": "Connection created successfully", + "200": { + "description": "dbt configuration deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "data": { + "message": { "type": "string", - "format": "uuid", - "description": "Created connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Success message", + "example": "dbt repository unlinked successfully" }, "success": { "type": "boolean", @@ -31434,32 +32585,32 @@ } }, "required": [ - "data", + "message", "success" ], - "description": "Create connection response", - "title": "ConnectionsCreateResponse" + "description": "dbt delete response", + "title": "ConnectionsDbtDeleteResponse" } } } }, - "400": { - "description": "Invalid request body or dialect" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found or dbt not configured" } } } }, - "/api/v1/connections/{id}": { + "/api/v1/connections/{connectionId}/dbt/environments": { "get": { - "description": "Fetch a single connection by ID.", - "operationId": "connectionsGet", - "summary": "Get connection", + "description": "List all dbt environments for a connection.", + "operationId": "connectionsDbtEnvironmentsList", + "summary": "List dbt environments", "tags": [ "Connections" ], @@ -31473,159 +32624,73 @@ }, "required": true, "description": "Connection ID", - "name": "id", + "name": "connectionId", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name" + ], + "default": "name", + "description": "Field to sort results by", + "example": "name" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" } ], - "responses": { - "200": { - "description": "Connection object", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connection": { - "type": "object", - "properties": { - "baseRole": { - "type": [ - "string", - "null" - ], - "description": "Default role for users on this connection", - "example": "QUERIER" - }, - "branchConnectionEnvironmentOverridesUserAttr": { - "type": [ - "boolean", - "null" - ], - "description": "Whether branch environments override user attributes", - "example": false - }, - "createdAt": { - "type": "string", - "description": "Timestamp when connection was created (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "database": { - "type": [ - "string", - "null" - ], - "description": "Database name", - "example": "analytics_db" - }, - "defaultSchema": { - "type": [ - "string", - "null" - ], - "description": "Default schema for the connection", - "example": "public" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when connection was deleted (ISO 8601)", - "example": null - }, - "dialect": { - "type": "string", - "enum": [ - "snowflake", - "bigquery", - "redshift", - "postgres", - "mysql", - "mariadb", - "databricks", - "databricks_lakebase", - "trino", - "athena", - "duckdb", - "motherduck", - "sqlserver", - "clickhouse", - "singlestore" - ], - "description": "Database dialect type", - "example": "snowflake" - }, - "environmentConnectionSwitchesSchemaModel": { - "type": [ - "boolean", - "null" - ], - "description": "Whether environment connections switch schema model", - "example": false - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection identifier", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "name": { - "type": "string", - "description": "Connection display name", - "example": "Production Snowflake" - }, - "updatedAt": { - "type": "string", - "description": "Timestamp when connection was last updated (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "userAttributeNameForConnectionEnvironments": { - "type": [ - "string", - "null" - ], - "description": "User attribute name used for connection environments", - "example": "region" - }, - "userAttributeValuesForDefaultEnvironment": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default user attribute values for the base environment", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "baseRole", - "branchConnectionEnvironmentOverridesUserAttr", - "createdAt", - "database", - "defaultSchema", - "deletedAt", - "dialect", - "environmentConnectionSwitchesSchemaModel", - "id", - "name", - "updatedAt", - "userAttributeNameForConnectionEnvironments", - "userAttributeValuesForDefaultEnvironment" - ], - "description": "Connection object", - "title": "Connection" - } - }, - "required": [ - "connection" - ], - "description": "Get connection response", - "title": "ConnectionsGetResponse" + "responses": { + "200": { + "description": "List of dbt environments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentListResponse" } } } @@ -31634,17 +32699,17 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied — caller lacks READ on the connection" + "description": "Permission denied or connection does not support dbt" }, "404": { - "description": "Connection does not exist" + "description": "Connection not found" } } }, - "patch": { - "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", - "operationId": "connectionsUpdate", - "summary": "Update connection", + "post": { + "description": "Create a new dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsCreate", + "summary": "Create dbt environment", "tags": [ "Connections" ], @@ -31658,115 +32723,59 @@ }, "required": true, "description": "Connection ID", - "name": "id", + "name": "connectionId", "in": "path" } ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "Default role to assign to this connection", - "example": "QUERIER" - }, - "environmentUserAttribute": { - "type": [ - "object", - "null" - ], - "properties": { - "attributeName": { - "type": "string", - "description": "Name of the user attribute for environment selection", - "example": "region" - }, - "defaultValues": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default values for the user attribute", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "attributeName", - "defaultValues" - ], - "description": "User attribute settings for connection environments" - }, - "passwordUnencrypted": { - "type": "string", - "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." - }, - "privateKey": { - "type": "string", - "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." - } - }, - "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", - "title": "ConnectionsUpdateBody" + "$ref": "#/components/schemas/DbtEnvironmentCreateBody" } } } }, "responses": { - "200": { - "description": "Connection updated successfully", + "201": { + "description": "dbt environment created successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Status message describing what was updated", - "example": "Updated connection default role." + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + { + "description": "Created dbt environment", + "title": "DbtEnvironmentCreateResponse" } - }, - "required": [ - "message", - "success" - ], - "description": "Update connection response", - "title": "ConnectionsUpdateResponse" + ] } } } }, "400": { - "description": "Invalid request body - at least one field must be provided" + "description": "Invalid request body" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied or connection does not support dbt" }, "404": { "description": "Connection not found" } } - }, - "delete": { - "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", - "operationId": "connectionsDelete", - "summary": "Delete connection", + } + }, + "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { + "put": { + "description": "Update an existing dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsUpdate", + "summary": "Update dbt environment", "tags": [ "Connections" ], @@ -31780,187 +32789,69 @@ }, "required": true, "description": "Connection ID", - "name": "id", + "name": "connectionId", "in": "path" - } - ], - "responses": { - "200": { - "description": "Connection moved to trash", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Status message describing the result", - "example": "Connection moved to trash." - }, - "success": { - "type": "boolean", - "description": "True when the connection was archived", - "example": true - } - }, - "required": [ - "message", - "success" - ], - "description": "Archive connection response", - "title": "ConnectionsDeleteResponse" - } - } - } - }, - "401": { - "description": "Authentication required" }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found" - }, - "410": { - "description": "Connection has already been archived" - } - } - } - }, - "/api/v1/connections/{connectionId}/dbt": { - "get": { - "operationId": "connectionsDbtGet", - "summary": "Get dbt configuration", - "tags": [ - "Connections" - ], - "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Environment ID", + "name": "environmentId", "in": "path" } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "dbt configuration for the connection", + "description": "dbt environment updated successfully", "content": { "application/json": { "schema": { - "anyOf": [ - { - "type": "object", - "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Whether relationships are auto-generated from dbt", - "example": true - }, - "branch": { - "type": "string", - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": "string", - "description": "dbt version being used", - "example": "Auto" - }, - "enableSemanticLayer": { - "type": "boolean", - "description": "Whether the dbt semantic layer integration is enabled", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Whether virtual schemas are enabled", - "example": false - }, - "projectRootPath": { - "type": [ - "string", - "null" - ], - "description": "Path to dbt project root", - "example": "dbt_project" - }, - "sshUrl": { - "type": "string", - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" - }, - "supportsDbt": { - "type": "boolean", - "enum": [ - true - ], - "description": "Indicates dbt is supported and configured", - "example": true - } - }, - "required": [ - "autogenRelationships", - "branch", - "dbtVersion", - "enableSemanticLayer", - "enableVirtualSchemas", - "projectRootPath", - "sshUrl", - "supportsDbt" - ], - "description": "dbt repository configuration response", - "title": "DbtConfiguredResponse" + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" }, { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Message explaining dbt status", - "example": "dbt not configured for this connection" - }, - "supportsDbt": { - "type": "boolean", - "description": "Whether the connection dialect supports dbt", - "example": true - } - }, - "required": [ - "message", - "supportsDbt" - ], - "description": "Response when dbt is not configured", - "title": "DbtNotConfiguredResponse" + "description": "Updated dbt environment", + "title": "DbtEnvironmentUpdateResponse" } - ], - "description": "dbt configuration response", - "title": "ConnectionsDbtGetResponse" + ] } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied or connection does not support dbt" }, "404": { - "description": "Connection not found" + "description": "Connection or environment not found" } } }, - "put": { - "operationId": "connectionsDbtUpdate", - "summary": "Update dbt configuration", + "delete": { + "description": "Delete a dbt environment from a connection.", + "operationId": "connectionsDbtEnvironmentsDelete", + "summary": "Delete dbt environment", "tags": [ "Connections" ], @@ -31976,130 +32867,154 @@ "description": "Connection ID", "name": "connectionId", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Automatically generate relationships from dbt", - "example": true - }, - "branch": { - "type": "string", - "minLength": 1, - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": [ - "string", - "null" - ], - "description": "dbt version to use. Supported: Auto, 1.10, 1.11", - "example": "1.11" - }, - "enableSemanticLayer": { - "type": "boolean", - "default": false, - "description": "Enable dbt semantic layer integration", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Enable virtual schemas from dbt", - "example": false - }, - "projectRootPath": { - "anyOf": [ - { - "type": "string", - "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" - }, - { - "type": "string", - "enum": [ - "" - ] - }, - { - "type": [ - "object", - "null" - ], - "enum": [ - null - ] - }, - { - "type": "null" - } - ], - "default": null, - "description": "Path to dbt project root within repository", - "example": "dbt_project" - }, - "rotateKeys": { - "type": "boolean", - "default": false, - "description": "Rotate SSH deploy keys", - "example": false - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" - } - }, - "required": [ - "autogenRelationships", - "branch", - "enableVirtualSchemas", - "sshUrl" - ], - "description": "dbt repository configuration", - "title": "ConnectionsDbtUpdateBody" + "responses": { + "200": { + "description": "dbt environment deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + } } } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" } - }, + } + } + }, + "/api/v1/connections/{connectionId}/schedules": { + "get": { + "operationId": "connectionsSchedulesList", + "summary": "List schema refresh schedules", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], "responses": { "200": { - "description": "dbt configuration updated successfully", + "description": "List of schema refresh schedules", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "dbt configuration updated successfully" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + "schedules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Schema refresh schedule object", + "title": "ConnectionSchedule" + }, + "description": "List of schema refresh schedules" } }, "required": [ - "message", - "success" + "schedules" ], - "description": "dbt update response", - "title": "ConnectionsDbtUpdateResponse" + "description": "List schedules response", + "title": "ConnectionsSchedulesListResponse" } } } }, - "400": { - "description": "Invalid request body or validation error" - }, "401": { "description": "Authentication required" }, @@ -32111,9 +33026,9 @@ } } }, - "delete": { - "operationId": "connectionsDbtDelete", - "summary": "Delete dbt configuration", + "post": { + "operationId": "connectionsSchedulesCreate", + "summary": "Create schema refresh schedule", "tags": [ "Connections" ], @@ -32131,35 +33046,118 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { + "type": "boolean", + "default": false, + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for creating a schema refresh schedule", + "title": "ConnectionsSchedulesCreateBody" + } + } + } + }, "responses": { - "200": { - "description": "dbt configuration deleted successfully", + "201": { + "description": "Schema refresh schedule created successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { + "connectionId": { "type": "string", - "description": "Success message", - "example": "dbt repository unlinked successfully" + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "success": { + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" } }, "required": [ - "message", - "success" + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" ], - "description": "dbt delete response", - "title": "ConnectionsDbtDeleteResponse" + "description": "Created schedule response", + "title": "ConnectionsSchedulesCreateResponse" } } } }, + "400": { + "description": "Invalid cron expression or timezone" + }, "401": { "description": "Authentication required" }, @@ -32167,16 +33165,15 @@ "description": "Permission denied - connection admin role required" }, "404": { - "description": "Connection not found or dbt not configured" + "description": "Connection not found" } } } }, - "/api/v1/connections/{connectionId}/dbt/environments": { + "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { "get": { - "description": "List all dbt environments for a connection.", - "operationId": "connectionsDbtEnvironmentsList", - "summary": "List dbt environments", + "operationId": "connectionsSchedulesGet", + "summary": "Get schema refresh schedule", "tags": [ "Connections" ], @@ -32196,67 +33193,88 @@ { "schema": { "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name" - ], - "default": "name", - "description": "Field to sort results by", - "example": "name" + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" } ], "responses": { "200": { - "description": "List of dbt environments", + "description": "Schema refresh schedule details", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DbtEnvironmentListResponse" + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Get schedule response", + "title": "ConnectionsSchedulesGetResponse" } } } @@ -32265,17 +33283,16 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied or connection does not support dbt" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection or schedule not found" } } }, - "post": { - "description": "Create a new dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsCreate", - "summary": "Create dbt environment", + "put": { + "operationId": "connectionsSchedulesUpdate", + "summary": "Update schema refresh schedule", "tags": [ "Connections" ], @@ -32291,57 +33308,146 @@ "description": "Connection ID", "name": "connectionId", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" } ], "requestBody": { - "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DbtEnvironmentCreateBody" + "type": "object", + "properties": { + "hardRefresh": { + "type": "boolean", + "default": false, + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for updating a schema refresh schedule", + "title": "ConnectionsSchedulesUpdateBody" } } } }, "responses": { - "201": { - "description": "dbt environment created successfully", + "200": { + "description": "Schema refresh schedule updated successfully", "content": { "application/json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentItem" + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - { - "description": "Created dbt environment", - "title": "DbtEnvironmentCreateResponse" + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" } - ] + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Updated schedule response", + "title": "ConnectionsSchedulesUpdateResponse" } } } }, "400": { - "description": "Invalid request body" + "description": "Invalid cron expression or timezone" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied or connection does not support dbt" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection or schedule not found" } } - } - }, - "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { - "put": { - "description": "Update an existing dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsUpdate", - "summary": "Update dbt environment", + }, + "delete": { + "operationId": "connectionsSchedulesDelete", + "summary": "Delete schema refresh schedule", "tags": [ "Connections" ], @@ -32362,118 +33468,253 @@ "schema": { "type": "string", "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Environment ID", - "name": "environmentId", + "description": "Schedule ID", + "name": "scheduleId", "in": "path" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" + "responses": { + "200": { + "description": "Schema refresh schedule deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "success" + ], + "description": "Delete schedule response", + "title": "ConnectionsSchedulesDeleteResponse" + } } } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" } - }, + } + } + }, + "/api/v1/connection-environments": { + "get": { + "operationId": "connectionEnvironmentsList", + "summary": "List connection environments", + "tags": [ + "Connections" + ], "responses": { "200": { - "description": "dbt environment updated successfully", + "description": "List of connection environments", "content": { "application/json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentItem" - }, - { - "description": "Updated dbt environment", - "title": "DbtEnvironmentUpdateResponse" + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" + }, + "description": "List of connection environments" } - ] + }, + "required": [ + "connectionEnvironments" + ], + "description": "List connection environments response", + "title": "ConnectionsEnvironmentsListResponse" } } } }, - "400": { - "description": "Invalid request body" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection or environment not found" + "description": "Permission denied - admin role required" } } }, - "delete": { - "description": "Delete a dbt environment from a connection.", - "operationId": "connectionsDbtEnvironmentsDelete", - "summary": "Delete dbt environment", + "post": { + "operationId": "connectionEnvironmentsCreate", + "summary": "Create connection environments", "tags": [ "Connections" ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" - }, - "required": true, - "description": "Environment ID", - "name": "environmentId", - "in": "path" + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "environmentConnectionIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "IDs of connections to use as environments", + "example": [ + "550e8400-e29b-41d4-a716-446655440002", + "550e8400-e29b-41d4-a716-446655440003" + ] + } + }, + "required": [ + "baseConnectionId", + "environmentConnectionIds" + ], + "description": "Request body for creating connection environments", + "title": "ConnectionsEnvironmentsCreateBody" + } + } } - ], + }, "responses": { - "200": { - "description": "dbt environment deleted successfully", + "201": { + "description": "Connection environments created successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" + }, + "description": "Created connection environments" + } + }, + "required": [ + "connectionEnvironments" + ], + "description": "Create connection environments response", + "title": "ConnectionsEnvironmentsCreateResponse" } } } }, + "400": { + "description": "Invalid request body or connection IDs" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied or connection does not support dbt" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection or environment not found" + "description": "Base connection or environment connection not found" } } } }, - "/api/v1/connections/{connectionId}/schedules": { - "get": { - "operationId": "connectionsSchedulesList", - "summary": "List schema refresh schedules", + "/api/v1/connection-environments/{id}": { + "put": { + "operationId": "connectionEnvironmentsUpdate", + "summary": "Update connection environment", "tags": [ "Connections" ], @@ -32482,119 +33723,82 @@ "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Connection environment ID", + "name": "id", "in": "path" } ], - "responses": { - "200": { - "description": "List of schema refresh schedules", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Schema refresh schedule object", - "title": "ConnectionSchedule" - }, - "description": "List of schema refresh schedules" + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "userAttributeValues" + ], + "description": "Request body for updating a connection environment", + "title": "ConnectionsEnvironmentsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Connection environment updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true } }, "required": [ - "schedules" + "success" ], - "description": "List schedules response", - "title": "ConnectionsSchedulesListResponse" + "description": "Update connection environment response", + "title": "ConnectionsEnvironmentsUpdateResponse" } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection environment not found" } } }, - "post": { - "operationId": "connectionsSchedulesCreate", - "summary": "Create schema refresh schedule", + "delete": { + "operationId": "connectionEnvironmentsDelete", + "summary": "Delete connection environment", "tags": [ "Connections" ], @@ -32603,909 +33807,579 @@ "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Connection environment ID", + "name": "id", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "hardRefresh": { - "type": "boolean", - "default": false, - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for creating a schema refresh schedule", - "title": "ConnectionsSchedulesCreateBody" - } - } - } - }, "responses": { - "201": { - "description": "Schema refresh schedule created successfully", + "200": { + "description": "Connection environment deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { + "success": { "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" + "description": "Whether the operation succeeded", + "example": true } }, "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" + "success" ], - "description": "Created schedule response", - "title": "ConnectionsSchedulesCreateResponse" + "description": "Delete connection environment response", + "title": "ConnectionsEnvironmentsDeleteResponse" } } } }, - "400": { - "description": "Invalid cron expression or timezone" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection environment not found" } } } }, - "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { + "/api/v1/content": { "get": { - "operationId": "connectionsSchedulesGet", - "summary": "Get schema refresh schedule", + "operationId": "contentList", + "summary": "List content", "tags": [ - "Connections" + "Content" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by creator user ID" + }, + "required": false, + "description": "Filter by creator user ID", + "name": "creatorId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by folder ID (cannot be used with path)" + }, + "required": false, + "description": "Filter by folder ID (cannot be used with path)", + "name": "folderId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (e.g., _count,labels)" + }, + "required": false, + "description": "Comma-separated list of fields to include (e.g., _count,labels)", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by folder path (cannot be used with folderId)", + "example": "/reports/sales" + }, + "required": false, + "description": "Filter by folder path (cannot be used with folderId)", + "name": "path", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Filter by share scope", + "example": "organization" + }, + "required": false, + "description": "Filter by share scope", + "name": "scope", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "asc" }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "enum": [ + "name", + "favorites" + ], + "description": "Field to sort by", + "example": "name" }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" } ], "responses": { "200": { - "description": "Schema refresh schedule details", + "description": "List of content (documents and folders)", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Get schedule response", - "title": "ConnectionsSchedulesGetResponse" + "$ref": "#/components/schemas/ContentListResponse" } } } }, + "400": { + "description": "Invalid query parameters (cannot use both folderId and path)" + }, "401": { "description": "Authentication required" }, - "403": { - "description": "Permission denied - connection admin role required" - }, "404": { - "description": "Connection or schedule not found" + "description": "Folder not found (when filtering by path)" } } - }, - "put": { - "operationId": "connectionsSchedulesUpdate", - "summary": "Update schema refresh schedule", + } + }, + "/api/v1/dashboards/{identifier}/download": { + "post": { + "operationId": "dashboardsDownload", + "summary": "Initiate dashboard download", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Target user membership ID (for org-scoped API keys)" }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "hardRefresh": { - "type": "boolean", - "default": false, - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for updating a schema refresh schedule", - "title": "ConnectionsSchedulesUpdateBody" + "$ref": "#/components/schemas/DashboardsDownloadBody" } } } }, "responses": { "200": { - "description": "Schema refresh schedule updated successfully", + "description": "Download job initiated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Updated schedule response", - "title": "ConnectionsSchedulesUpdateResponse" + "$ref": "#/components/schemas/DashboardsDownloadResponse" } } } }, "400": { - "description": "Invalid cron expression or timezone" + "description": "Invalid request body or filter configuration" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - cannot download this dashboard" }, "404": { - "description": "Connection or schedule not found" + "description": "Dashboard not found" + }, + "409": { + "description": "Download already in progress for this dashboard" + }, + "500": { + "description": "Failed to initiate download" } } - }, - "delete": { - "operationId": "connectionsSchedulesDelete", - "summary": "Delete schema refresh schedule", + } + }, + "/api/v1/dashboards/{identifier}/download/{jobId}": { + "get": { + "operationId": "dashboardsDownloadFile", + "summary": "Get download file", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" }, "required": true, - "description": "Schedule ID", - "name": "scheduleId", + "description": "Download job ID (UUID)", + "name": "jobId", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "responses": { "200": { - "description": "Schema refresh schedule deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete schedule response", - "title": "ConnectionsSchedulesDeleteResponse" - } - } - } + "description": "File ready - binary content streamed" + }, + "202": { + "description": "Download job still in progress" }, "401": { "description": "Authentication required" }, - "403": { - "description": "Permission denied - connection admin role required" - }, "404": { - "description": "Connection or schedule not found" + "description": "Dashboard or download job not found" + }, + "410": { + "description": "Download job failed" + }, + "500": { + "description": "Failed to retrieve download artifact" } } } }, - "/api/v1/connection-environments": { + "/api/v1/dashboards/{identifier}/download/{jobId}/status": { "get": { - "operationId": "connectionEnvironmentsList", - "summary": "List connection environments", - "tags": [ - "Connections" - ], - "responses": { - "200": { - "description": "List of connection environments", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "List of connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "List connection environments response", - "title": "ConnectionsEnvironmentsListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - } - } - }, - "post": { - "operationId": "connectionEnvironmentsCreate", - "summary": "Create connection environments", + "operationId": "dashboardsDownloadStatus", + "summary": "Get download job status", "tags": [ - "Connections" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "environmentConnectionIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "IDs of connections to use as environments", - "example": [ - "550e8400-e29b-41d4-a716-446655440002", - "550e8400-e29b-41d4-a716-446655440003" - ] - } - }, - "required": [ - "baseConnectionId", - "environmentConnectionIds" - ], - "description": "Request body for creating connection environments", - "title": "ConnectionsEnvironmentsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Connection environments created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "Created connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "Create connection environments response", - "title": "ConnectionsEnvironmentsCreateResponse" - } - } - } + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" }, - "400": { - "description": "Invalid request body or connection IDs" + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Download job status" }, "401": { "description": "Authentication required" }, - "403": { - "description": "Permission denied - admin role required" - }, "404": { - "description": "Base connection or environment connection not found" + "description": "Dashboard or download job not found" } } } }, - "/api/v1/connection-environments/{id}": { - "put": { - "operationId": "connectionEnvironmentsUpdate", - "summary": "Update connection environment", + "/api/v1/dashboards/{identifier}/filters": { + "get": { + "operationId": "dashboardsGetFilters", + "summary": "Get dashboard filters", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection environment ID", - "name": "id", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "userAttributeValues" - ], - "description": "Request body for updating a connection environment", - "title": "ConnectionsEnvironmentsUpdateBody" - } - } - } - }, "responses": { "200": { - "description": "Connection environment updated successfully", + "description": "Dashboard filter and control configuration", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Update connection environment response", - "title": "ConnectionsEnvironmentsUpdateResponse" + "$ref": "#/components/schemas/DashboardFiltersResponse" } } } }, - "400": { - "description": "Invalid request body" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - VIEWER role required" }, "404": { - "description": "Connection environment not found" + "description": "Dashboard not found" } } }, - "delete": { - "operationId": "connectionEnvironmentsDelete", - "summary": "Delete connection environment", + "patch": { + "operationId": "dashboardsUpdateFilters", + "summary": "Update dashboard filters", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection environment ID", - "name": "id", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" + } + } + } + }, "responses": { "200": { - "description": "Connection environment deleted successfully", + "description": "Filters updated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete connection environment response", - "title": "ConnectionsEnvironmentsDeleteResponse" + "$ref": "#/components/schemas/DashboardFiltersResponse" } } } }, + "400": { + "description": "Invalid request body - must include at least one filter, control, or filterOrder" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - EDITOR role required" }, "404": { - "description": "Connection environment not found" + "description": "Dashboard not found or document does not have a dashboard" + }, + "409": { + "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." } } } }, - "/api/v1/content": { + "/api/v1/documents": { "get": { - "operationId": "contentList", - "summary": "List content", + "operationId": "documentsList", + "summary": "List documents", "tags": [ - "Content" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 + "format": "uuid", + "description": "Filter by creator membership ID" }, "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", + "description": "Filter by creator membership ID", + "name": "creatorId", "in": "query" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Filter by creator user ID" + "description": "Cursor for pagination" }, "required": false, - "description": "Filter by creator user ID", - "name": "creatorId", + "description": "Cursor for pagination", + "name": "cursor", "in": "query" }, { "schema": { "type": "string", "format": "uuid", - "description": "Filter by folder ID (cannot be used with path)" + "description": "Filter by folder ID" }, "required": false, - "description": "Filter by folder ID (cannot be used with path)", + "description": "Filter by folder ID", "name": "folderId", "in": "query" }, { "schema": { "type": "string", - "description": "Comma-separated list of fields to include (e.g., _count,labels)" + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "example": "_count,labels" }, "required": false, - "description": "Comma-separated list of fields to include (e.g., _count,labels)", + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", "name": "include", "in": "query" }, { "schema": { "type": "string", - "description": "Filter by folder path (cannot be used with folderId)", - "example": "/reports/sales" + "description": "Comma-separated list of label names to filter by", + "example": "verified,important" }, "required": false, - "description": "Filter by folder path (cannot be used with folderId)", - "name": "path", + "description": "Comma-separated list of label names to filter by", + "name": "labels", "in": "query" }, { "schema": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Filter by share scope", - "example": "organization" + "type": "integer", + "exclusiveMinimum": 0, + "default": 50, + "description": "Number of records per page" }, "required": false, - "description": "Filter by share scope", - "name": "scope", + "description": "Number of records per page", + "name": "pageSize", "in": "query" }, { @@ -33515,8 +34389,8 @@ "asc", "desc" ], - "description": "Sort direction", - "example": "asc" + "default": "asc", + "description": "Sort direction" }, "required": false, "description": "Sort direction", @@ -33528,269 +34402,318 @@ "type": "string", "enum": [ "name", - "favorites" + "favorites", + "updatedAt", + "visits" ], - "description": "Field to sort by", - "example": "name" + "default": "name", + "description": "Field to sort by" }, "required": false, "description": "Field to sort by", "name": "sortField", "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter documents visible to this membership ID" + }, + "required": false, + "description": "Filter documents visible to this membership ID", + "name": "userId", + "in": "query" } ], "responses": { "200": { - "description": "List of content (documents and folders)", + "description": "Paginated list of documents", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ContentListResponse" + "$ref": "#/components/schemas/DocumentsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + } + } + }, + "post": { + "operationId": "documentsCreate", + "summary": "Create document", + "tags": [ + "Documents" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateResponse" } } } }, "400": { - "description": "Invalid query parameters (cannot use both folderId and path)" + "description": "Invalid request body" }, "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied" + }, "404": { - "description": "Folder not found (when filtering by path)" + "description": "Model or branch not found" } } } }, - "/api/v1/dashboards/{identifier}/download": { - "post": { - "operationId": "dashboardsDownload", - "summary": "Initiate dashboard download", + "/api/v1/documents/{identifier}": { + "get": { + "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", + "operationId": "documentsGet", + "summary": "Get document", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + } + ], + "responses": { + "200": { + "description": "Document details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetResponse" + } + } + } }, + "400": { + "description": "Analysis documents are not supported" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions to view the document" + }, + "404": { + "description": "Document not found" + } + } + }, + "put": { + "deprecated": true, + "description": "**Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Removal scheduled per the `Sunset` response header.\n\nUpdates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", + "operationId": "documentsPut", + "summary": "Replace document (full replacement)", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsDownloadBody" + "$ref": "#/components/schemas/DocumentsPutBody" } } } }, "responses": { "200": { - "description": "Download job initiated successfully", + "description": "Document replaced successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsDownloadResponse" + "$ref": "#/components/schemas/DocumentsPutResponse" } } } }, "400": { - "description": "Invalid request body or filter configuration" + "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - cannot download this dashboard" + "description": "Insufficient permissions to update the document" }, "404": { - "description": "Dashboard not found" + "description": "Document not found" }, "409": { - "description": "Download already in progress for this dashboard" - }, - "500": { - "description": "Failed to initiate download" + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } - } - }, - "/api/v1/dashboards/{identifier}/download/{jobId}": { - "get": { - "operationId": "dashboardsDownloadFile", - "summary": "Get download file", + }, + "patch": { + "deprecated": true, + "description": "**Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Removal scheduled per the `Sunset` response header.\n\nUpdates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", + "operationId": "documentsUpdate", + "summary": "Rename document", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "File ready - binary content streamed" + "description": "Document updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateResponse" + } + } + } }, - "202": { - "description": "Download job still in progress" + "400": { + "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" }, "401": { "description": "Authentication required" }, - "404": { - "description": "Dashboard or download job not found" + "403": { + "description": "Permission denied - EDITOR role required" }, - "410": { - "description": "Download job failed" + "404": { + "description": "Document not found" }, - "500": { - "description": "Failed to retrieve download artifact" + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } - } - }, - "/api/v1/dashboards/{identifier}/download/{jobId}/status": { - "get": { - "operationId": "dashboardsDownloadStatus", - "summary": "Get download job status", - "tags": [ - "Dashboards" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" - }, - "required": true, - "description": "Dashboard identifier (short ID or UUID)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", - "in": "path" - }, + }, + "delete": { + "operationId": "documentsDelete", + "summary": "Delete document", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], "responses": { "200": { - "description": "Download job status" + "description": "Document deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } }, "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - MANAGER role required" + }, "404": { - "description": "Dashboard or download job not found" + "description": "Document not found" } } } }, - "/api/v1/dashboards/{identifier}/filters": { + "/api/v1/documents/{identifier}/queries": { "get": { - "operationId": "dashboardsGetFilters", - "summary": "Get dashboard filters", + "operationId": "documentsGetQueries", + "summary": "List document queries", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { "200": { - "description": "Dashboard filter and control configuration", + "description": "List of queries in the document", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" + "$ref": "#/components/schemas/DocumentsGetQueriesResponse" } } } @@ -33799,85 +34722,73 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - VIEWER role required" + "description": "Permission denied" }, "404": { - "description": "Dashboard not found" + "description": "Document not found" } } - }, - "patch": { - "operationId": "dashboardsUpdateFilters", - "summary": "Update dashboard filters", + } + }, + "/api/v1/documents/{identifier}/move": { + "put": { + "operationId": "documentsMove", + "summary": "Move document", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" + "$ref": "#/components/schemas/DocumentsMoveBody" } } } }, "responses": { "200": { - "description": "Filters updated successfully", + "description": "Document moved successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body - must include at least one filter, control, or filterOrder" + "description": "Invalid folder path or scope" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Dashboard not found or document does not have a dashboard" - }, - "409": { - "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." + "description": "Document or folder not found" } } } }, - "/api/v1/documents": { + "/api/v1/documents/{identifier}/permissions": { "get": { - "operationId": "documentsList", - "summary": "List documents", + "operationId": "documentsGetPermissions", + "summary": "Get document permissions", "tags": [ "Documents" ], @@ -33885,175 +34796,157 @@ { "schema": { "type": "string", - "format": "uuid", - "description": "Filter by creator membership ID" - }, - "required": false, - "description": "Filter by creator membership ID", - "name": "creatorId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Cursor for pagination", - "name": "cursor", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Filter by folder ID" - }, - "required": false, - "description": "Filter by folder ID", - "name": "folderId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "example": "_count,labels" - }, - "required": false, - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of label names to filter by", - "example": "verified,important" - }, - "required": false, - "description": "Comma-separated list of label names to filter by", - "name": "labels", - "in": "query" - }, - { - "schema": { - "type": "integer", - "exclusiveMinimum": 0, - "default": 50, - "description": "Number of records per page" + "description": "User membership ID to check permissions for" }, - "required": false, - "description": "Number of records per page", - "name": "pageSize", + "required": true, + "description": "User membership ID to check permissions for", + "name": "userId", "in": "query" + } + ], + "responses": { + "200": { + "description": "User permissions for the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" + } + } + } }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" + "401": { + "description": "Authentication required" }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "favorites", - "updatedAt", - "visits" - ], - "default": "name", - "description": "Field to sort by" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" + "403": { + "description": "Permission denied" }, + "404": { + "description": "Document or user not found" + } + } + }, + "put": { + "operationId": "documentsUpdatePermissionSettings", + "summary": "Update document permission settings", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Filter documents visible to this membership ID" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Filter documents visible to this membership ID", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" + } + } + } + }, "responses": { "200": { - "description": "Paginated list of documents", + "description": "Permission settings updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsListResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" } } }, "post": { - "operationId": "documentsCreate", - "summary": "Create document", + "operationId": "documentsAddPermits", + "summary": "Add document permits", "tags": [ "Documents" ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateBody" + "$ref": "#/components/schemas/DocumentsAddPermitsBody" } } } }, "responses": { - "201": { - "description": "Document created successfully", + "200": { + "description": "Permissions added successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body" + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Model or branch not found" + "description": "Document not found" } } - } - }, - "/api/v1/documents/{identifier}": { - "get": { - "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", - "operationId": "documentsGet", - "summary": "Get document", + }, + "patch": { + "operationId": "documentsUpdatePermits", + "summary": "Update document permits", "tags": [ "Documents" ], @@ -34070,35 +34963,43 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" + } + } + } + }, "responses": { "200": { - "description": "Document details", + "description": "Permissions updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsGetResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Analysis documents are not supported" + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions to view the document" + "description": "Permission denied - MANAGER role required" }, "404": { "description": "Document not found" } } }, - "put": { - "description": "Updates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", - "operationId": "documentsPut", - "summary": "Replace document (full replacement)", + "delete": { + "operationId": "documentsRevokePermits", + "summary": "Revoke document permits", "tags": [ "Documents" ], @@ -34119,43 +35020,41 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsPutBody" + "$ref": "#/components/schemas/DocumentsRevokePermitsBody" } } } }, "responses": { "200": { - "description": "Document replaced successfully", + "description": "Permissions revoked successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsPutResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions to update the document" + "description": "Permission denied - MANAGER role required" }, "404": { "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } - }, - "patch": { - "description": "Updates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", - "operationId": "documentsUpdate", - "summary": "Rename document", + } + }, + "/api/v1/documents/{identifier}/draft": { + "post": { + "operationId": "documentsCreateDraft", + "summary": "Create document draft", "tags": [ "Documents" ], @@ -34176,24 +35075,24 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsUpdateBody" + "$ref": "#/components/schemas/DocumentsCreateDraftBody" } } } }, "responses": { "200": { - "description": "Document updated successfully", + "description": "Draft created or existing draft returned", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsUpdateResponse" + "$ref": "#/components/schemas/DocumentsCreateDraftResponse" } } } }, "400": { - "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" + "description": "Document is not eligible for publishing workflow" }, "401": { "description": "Authentication required" @@ -34202,16 +35101,13 @@ "description": "Permission denied - EDITOR role required" }, "404": { - "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" + "description": "Document or branch not found" } } }, "delete": { - "operationId": "documentsDelete", - "summary": "Delete document", + "operationId": "documentsDiscardDraft", + "summary": "Discard document draft", "tags": [ "Documents" ], @@ -34228,13 +35124,22 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDiscardDraftBody" + } + } + } + }, "responses": { "200": { - "description": "Document deleted successfully", + "description": "Draft discarded successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" } } } @@ -34243,18 +35148,19 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { - "description": "Document not found" + "description": "Document or draft not found" } } } }, - "/api/v1/documents/{identifier}/queries": { + "/api/v1/documents/{identifier}/drafts": { "get": { - "operationId": "documentsGetQueries", - "summary": "List document queries", + "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", + "operationId": "documentsListDrafts", + "summary": "List document drafts", "tags": [ "Documents" ], @@ -34269,24 +35175,38 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "example": "archived" + }, + "required": false, + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "name": "include", + "in": "query" } ], "responses": { "200": { - "description": "List of queries in the document", + "description": "List of drafts for the document", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsGetQueriesResponse" + "$ref": "#/components/schemas/DocumentsListDraftsResponse" } } } }, + "400": { + "description": "Invalid query parameters" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to view the document" }, "404": { "description": "Document not found" @@ -34294,10 +35214,10 @@ } } }, - "/api/v1/documents/{identifier}/move": { - "put": { - "operationId": "documentsMove", - "summary": "Move document", + "/api/v1/documents/{identifier}/duplicate": { + "post": { + "operationId": "documentsDuplicate", + "summary": "Duplicate document", "tags": [ "Documents" ], @@ -34312,36 +35232,47 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsMoveBody" + "$ref": "#/components/schemas/DocumentsDuplicateBody" } } } }, "responses": { - "200": { - "description": "Document moved successfully", + "201": { + "description": "Document duplicated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsDuplicateResponse" } } } }, "400": { - "description": "Invalid folder path or scope" + "description": "Invalid name or folder path" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document or folder not found" @@ -34349,10 +35280,10 @@ } } }, - "/api/v1/documents/{identifier}/permissions": { - "get": { - "operationId": "documentsGetPermissions", - "summary": "Get document permissions", + "/api/v1/documents/{identifier}/favorite": { + "put": { + "operationId": "documentsAddFavorite", + "summary": "Add document to favorites", "tags": [ "Documents" ], @@ -34372,24 +35303,17 @@ "schema": { "type": "string", "format": "uuid", - "description": "User membership ID to check permissions for" + "description": "Target user membership ID (for org-scoped API keys)" }, - "required": true, - "description": "User membership ID to check permissions for", + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", "name": "userId", "in": "query" } ], "responses": { - "200": { - "description": "User permissions for the document", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" - } - } - } + "204": { + "description": "Favorite added successfully" }, "401": { "description": "Authentication required" @@ -34398,13 +35322,13 @@ "description": "Permission denied" }, "404": { - "description": "Document or user not found" + "description": "Document not found" } } }, - "put": { - "operationId": "documentsUpdatePermissionSettings", - "summary": "Update document permission settings", + "delete": { + "operationId": "documentsRemoveFavorite", + "summary": "Remove document from favorites", "tags": [ "Documents" ], @@ -34419,45 +35343,39 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permission settings updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } }, - "400": { - "description": "Invalid request body" + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Favorite removed successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document not found" } } - }, - "post": { - "operationId": "documentsAddPermits", - "summary": "Add document permits", + } + }, + "/api/v1/documents/{identifier}/labels": { + "patch": { + "operationId": "documentsBulkUpdateLabels", + "summary": "Bulk update document labels", "tags": [ "Documents" ], @@ -34472,45 +35390,58 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsAddPermitsBody" + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" } } } }, "responses": { "200": { - "description": "Permissions added successfully", + "description": "Labels updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" } } } }, "400": { - "description": "Invalid request body - userIds or userGroupIds required" + "description": "Invalid request - at least one label must be specified" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document not found" } } - }, - "patch": { - "operationId": "documentsUpdatePermits", - "summary": "Update document permits", + } + }, + "/api/v1/documents/{identifier}/labels/{labelName}": { + "put": { + "operationId": "documentsAddLabel", + "summary": "Add label to document", "tags": [ "Documents" ], @@ -34518,52 +35449,55 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" - } - } - } - }, "responses": { - "200": { - "description": "Permissions updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" + "204": { + "description": "Label added successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { - "description": "Document not found" + "description": "Document or label not found" } } }, "delete": { - "operationId": "documentsRevokePermits", - "summary": "Revoke document permits", + "operationId": "documentsRemoveLabel", + "summary": "Remove label from document", "tags": [ "Documents" ], @@ -34571,43 +35505,46 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsRevokePermitsBody" - } - } - } - }, "responses": { - "200": { - "description": "Permissions revoked successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" + "204": { + "description": "Label removed successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document not found" @@ -34615,10 +35552,10 @@ } } }, - "/api/v1/documents/{identifier}/draft": { - "post": { - "operationId": "documentsCreateDraft", - "summary": "Create document draft", + "/api/v1/documents/{identifier}/transfer-ownership": { + "put": { + "operationId": "documentsTransferOwnership", + "summary": "Transfer document ownership", "tags": [ "Documents" ], @@ -34639,39 +35576,41 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftBody" + "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" } } } }, "responses": { "200": { - "description": "Draft created or existing draft returned", + "description": "Ownership transferred successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Document is not eligible for publishing workflow" + "description": "Invalid user ID" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Permission denied - MANAGER role or owner required" }, "404": { - "description": "Document or branch not found" + "description": "Document or user not found" } } - }, - "delete": { - "operationId": "documentsDiscardDraft", - "summary": "Discard document draft", + } + }, + "/api/v1/documents/{identifier}/access-list": { + "get": { + "operationId": "documentsAccessList", + "summary": "List document access principals", "tags": [ "Documents" ], @@ -34679,31 +35618,101 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction (default: asc)", + "example": "desc" + }, + "required": false, + "description": "Sort direction (default: asc)", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "direct", + "folder" + ], + "description": "Filter by access source: direct or folder" + }, + "required": false, + "description": "Filter by access source: direct or folder", + "name": "accessSource", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "user", + "userGroup" + ], + "description": "Filter by principal type: user or userGroup" }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" + "required": false, + "description": "Filter by principal type: user or userGroup", + "name": "type", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftBody" - } - } - } - }, "responses": { "200": { - "description": "Draft discarded successfully", + "description": "List of users and groups with access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" + "$ref": "#/components/schemas/DocumentsAccessListResponse" } } } @@ -34712,19 +35721,19 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied" + "description": "Permission denied - VIEWER role required" }, "404": { - "description": "Document or draft not found" + "description": "Document not found" } } } }, - "/api/v1/documents/{identifier}/drafts": { + "/api/v1/documents/{identifier}/favorites": { "get": { - "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", - "operationId": "documentsListDrafts", - "summary": "List document drafts", + "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", + "operationId": "documentsListFavorites", + "summary": "List users who favorited the document", "tags": [ "Documents" ], @@ -34743,22 +35752,52 @@ { "schema": { "type": "string", - "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", - "example": "archived" + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" }, "required": false, - "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", - "name": "include", + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "example": "desc" + }, + "required": false, + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "name": "sortDirection", "in": "query" } ], "responses": { "200": { - "description": "List of drafts for the document", + "description": "Paginated list of users who favorited the document", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsListDraftsResponse" + "$ref": "#/components/schemas/DocumentsListFavoritesResponse" } } } @@ -34770,7 +35809,7 @@ "description": "Authentication required" }, "403": { - "description": "Insufficient permissions to view the document" + "description": "Permission denied — caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" }, "404": { "description": "Document not found" @@ -34778,76 +35817,58 @@ } } }, - "/api/v1/documents/{identifier}/duplicate": { + "/api/v2/documents": { "post": { - "operationId": "documentsDuplicate", - "summary": "Duplicate document", + "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nWhen `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When `containers` is present, it fully defines the layout — tiles it does not reference are stored but not rendered.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to existing content).", + "operationId": "documentsV2Create", + "summary": "Create document", "tags": [ "Documents" ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateBody" + "$ref": "#/components/schemas/DocumentsV2CreateBody" } } } }, "responses": { "201": { - "description": "Document duplicated successfully", + "description": "Document created and published successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateResponse" + "$ref": "#/components/schemas/DocumentsV2CreateResponse" } } } }, "400": { - "description": "Invalid name or folder path" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to create a document on this model." }, "404": { - "description": "Document or folder not found" + "description": "Base model or branch not found." + }, + "405": { + "description": "Method not allowed." } } } }, - "/api/v1/documents/{identifier}/favorite": { - "put": { - "operationId": "documentsAddFavorite", - "summary": "Add document to favorites", + "/api/v2/documents/{identifier}": { + "get": { + "description": "Read the document's current draft state (or the published state if no draft exists). Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2Get", + "summary": "Read document state", "tags": [ "Documents" ], @@ -34855,91 +35876,46 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { - "204": { - "description": "Favorite added successfully" + "200": { + "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2ReadResponse" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to read the document." }, "404": { - "description": "Document not found" - } - } - }, - "delete": { - "operationId": "documentsRemoveFavorite", - "summary": "Remove document from favorites", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Favorite removed successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" + "description": "Document not found." }, - "404": { - "description": "Document not found" + "422": { + "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." } } } }, - "/api/v1/documents/{identifier}/labels": { + "/api/v2/documents/{identifier}/draft": { "patch": { - "operationId": "documentsBulkUpdateLabels", - "summary": "Bulk update document labels", + "description": "Create a new draft on the published document and apply the patch. No auto-publish — the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", + "operationId": "documentsV2PatchDraft", + "summary": "Create draft and patch document", "tags": [ "Documents" ], @@ -34947,65 +35923,64 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" + "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" } } } }, "responses": { "200": { - "description": "Labels updated successfully", + "description": "Draft created and patch applied successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" } } } }, "400": { - "description": "Invalid request - at least one label must be specified" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to update the document." }, "404": { - "description": "Document not found" + "description": "Document or branch not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." } } } }, - "/api/v1/documents/{identifier}/labels/{labelName}": { - "put": { - "operationId": "documentsAddLabel", - "summary": "Add label to document", + "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { + "get": { + "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2GetDraft", + "summary": "Read draft state", "tags": [ "Documents" ], @@ -35013,55 +35988,55 @@ { "schema": { "type": "string", - "description": "Document identifier", - "example": "abc123" + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" }, "required": true, - "description": "Document identifier", - "name": "identifier", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", "in": "path" }, { "schema": { "type": "string", - "description": "Label name", - "example": "verified" + "description": "Published document identifier.", + "example": "abc123" }, "required": true, - "description": "Label name", - "name": "labelName", + "description": "Published document identifier.", + "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { - "204": { - "description": "Label added successfully" + "200": { + "description": "Draft state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2ReadResponse" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to read the draft." }, "404": { - "description": "Document or label not found" + "description": "Document or draft not found." + }, + "422": { + "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." } } }, - "delete": { - "operationId": "documentsRemoveLabel", - "summary": "Remove label from document", + "patch": { + "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, no publish.", + "operationId": "documentsV2PatchDraftByIdentifier", + "summary": "Patch draft", "tags": [ "Documents" ], @@ -35069,69 +36044,22 @@ { "schema": { "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "required": true, - "description": "Document identifier", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" }, "required": true, - "description": "Label name", - "name": "labelName", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", "in": "path" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Label removed successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/transfer-ownership": { - "put": { - "operationId": "documentsTransferOwnership", - "summary": "Transfer document ownership", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Published document identifier.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Published document identifier.", "name": "identifier", "in": "path" } @@ -35140,41 +36068,51 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" } } } }, "responses": { "200": { - "description": "Ownership transferred successfully", + "description": "Patch applied to draft successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" } } } }, "400": { - "description": "Invalid user ID" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied - MANAGER role or owner required" + "description": "Insufficient permissions to update the draft." }, "404": { - "description": "Document or user not found" + "description": "Document or draft not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." } } } }, - "/api/v1/documents/{identifier}/access-list": { - "get": { - "operationId": "documentsAccessList", - "summary": "List document access principals", + "/api/v2/documents/{identifier}/draft/publish": { + "post": { + "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body — the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", + "operationId": "documentsV2PublishDraft", + "summary": "Publish draft", "tags": [ "Documents" ], @@ -35182,593 +36120,574 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" + } + ], + "responses": { + "200": { + "description": "Draft published successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" + } + } + } }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" + "400": { + "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction (default: asc)", - "example": "desc" - }, - "required": false, - "description": "Sort direction (default: asc)", - "name": "sortDirection", - "in": "query" + "401": { + "description": "Authentication required." }, - { - "schema": { - "type": "string", - "description": "Field to sort results by" - }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" + "403": { + "description": "Insufficient permissions to publish the draft." }, - { - "schema": { - "type": "string", - "enum": [ - "direct", - "folder" - ], - "description": "Filter by access source: direct or folder" - }, - "required": false, - "description": "Filter by access source: direct or folder", - "name": "accessSource", - "in": "query" + "404": { + "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." }, - { - "schema": { - "type": "string", - "enum": [ - "user", - "userGroup" - ], - "description": "Filter by principal type: user or userGroup" - }, - "required": false, - "description": "Filter by principal type: user or userGroup", - "name": "type", - "in": "query" + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document." } + } + } + }, + "/api/v1/embed/sso/generate-session": { + "post": { + "operationId": "embedSsoGenerateSession", + "summary": "Generate embedded SSO session", + "tags": [ + "Embed" ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" + } + } + } + }, "responses": { "200": { - "description": "List of users and groups with access", + "description": "Session token generated", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsAccessListResponse" + "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" } } } }, + "400": { + "description": "Invalid request body" + }, "401": { - "description": "Authentication required" + "description": "Authentication required (API key with embed scope)" }, "403": { - "description": "Permission denied - VIEWER role required" - }, - "404": { - "description": "Document not found" + "description": "Permission denied - embed not enabled" } } } }, - "/api/v1/documents/{identifier}/favorites": { + "/api/v1/ai/eval/prompt-sets": { "get": { - "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", - "operationId": "documentsListFavorites", - "summary": "List users who favorited the document", + "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", + "operationId": "aiEvalPromptSetsList", + "summary": "List eval prompt sets", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 + "enum": [ + "true", + "false" + ], + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "example": "false" }, "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "name": "archived", "in": "query" }, { "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction by favoritedAt (default: asc — oldest first)", - "example": "desc" + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." }, "required": false, - "description": "Sort direction by favoritedAt (default: asc — oldest first)", - "name": "sortDirection", + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", + "name": "model_ids", "in": "query" } ], "responses": { "200": { - "description": "Paginated list of users who favorited the document", + "description": "List of prompt sets, sorted alphabetically by name.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsListFavoritesResponse" + "$ref": "#/components/schemas/EvalPromptSetsListResponse" } } } }, "400": { - "description": "Invalid query parameters" + "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied — caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" + "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document not found" + "description": "No eval-accessible models for this caller.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } } } - } - }, - "/api/v2/documents": { + }, "post": { - "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to existing content).", - "operationId": "documentsV2Create", - "summary": "Create document", + "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", + "operationId": "aiEvalPromptSetsCreate", + "summary": "Create an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateBody" + "$ref": "#/components/schemas/EvalPromptSetsCreateBody" } } } }, "responses": { "201": { - "description": "Document created and published successfully.", + "description": "Prompt set created successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateResponse" + "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" } } } }, "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required." + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Insufficient permissions to create a document on this model." - }, - "404": { - "description": "Base model or branch not found." - }, - "405": { - "description": "Method not allowed." + "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } } } } }, - "/api/v2/documents/{identifier}": { + "/api/v1/ai/eval/prompt-sets/{promptSetId}": { "get": { - "description": "Read the document's current draft state (or the published state if no draft exists). Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", - "operationId": "documentsV2Get", - "summary": "Read document state", + "description": "Get a single prompt set with all of its prompts.", + "operationId": "aiEvalPromptSetsGet", + "summary": "Get an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], "responses": { "200": { - "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", + "description": "Prompt set details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsGetResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2ReadResponse" + "$ref": "#/components/schemas/EvalApiError403" } } } }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to read the document." - }, "404": { - "description": "Document not found." - }, - "422": { - "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } } } - } - }, - "/api/v2/documents/{identifier}/draft": { + }, "patch": { - "description": "Create a new draft on the published document and apply the patch. No auto-publish — the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", - "operationId": "documentsV2PatchDraft", - "summary": "Create draft and patch document", + "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list — existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", + "operationId": "aiEvalPromptSetsUpdate", + "summary": "Update an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" + "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" } } } }, "responses": { "200": { - "description": "Draft created and patch applied successfully.", + "description": "Prompt set updated successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" } } } }, "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to update the document." - }, - "404": { - "description": "Document or branch not found." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." - }, - "422": { - "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." - } - } - } - }, - "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { - "get": { - "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", - "operationId": "documentsV2GetDraft", - "summary": "Read draft state", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "example": "def456" - }, - "required": true, - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "name": "draftIdentifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Published document identifier.", - "example": "abc123" - }, - "required": true, - "description": "Published document identifier.", - "name": "identifier", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Draft state.", + "description": "Invalid request body.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2ReadResponse" + "$ref": "#/components/schemas/EvalApiError400" } } } }, "401": { - "description": "Authentication required." + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Insufficient permissions to read the draft." + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document or draft not found." + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } }, "422": { - "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." + "description": "A `prompts[].id` in the request does not belong to this prompt set.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } } } }, - "patch": { - "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, no publish.", - "operationId": "documentsV2PatchDraftByIdentifier", - "summary": "Patch draft", + "delete": { + "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent — retrying drains any remaining runs.", + "operationId": "aiEvalPromptSetsArchive", + "summary": "Archive an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "example": "def456" - }, - "required": true, - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "name": "draftIdentifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Published document identifier.", - "example": "abc123" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Published document identifier.", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" - } - } - } - }, "responses": { "200": { - "description": "Patch applied to draft successfully.", + "description": "Prompt set archived successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" } } } }, "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required." + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Insufficient permissions to update the draft." + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document or draft not found." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } }, - "422": { - "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." + "500": { + "description": "Archive committed but a run-cancellation failed; the set is already archived — safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } } } } }, - "/api/v2/documents/{identifier}/draft/publish": { + "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { "post": { - "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body — the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", - "operationId": "documentsV2PublishDraft", - "summary": "Publish draft", + "description": "Restore an archived prompt set.", + "operationId": "aiEvalPromptSetsUnarchive", + "summary": "Restore an archived eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], "responses": { "200": { - "description": "Draft published successfully.", + "description": "Prompt set restored successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" + "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" } } } }, "400": { - "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required." + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Insufficient permissions to publish the draft." - }, - "404": { - "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document." - } - } - } - }, - "/api/v1/embed/sso/generate-session": { - "post": { - "operationId": "embedSsoGenerateSession", - "summary": "Generate embedded SSO session", - "tags": [ - "Embed" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } } } - } - }, - "responses": { - "200": { - "description": "Session token generated", + }, + "404": { + "description": "Prompt set not found.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" + "$ref": "#/components/schemas/EvalApiError404" } } } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required (API key with embed scope)" - }, - "403": { - "description": "Permission denied - embed not enabled" } } } }, - "/api/v1/ai/eval/prompt-sets": { + "/api/v1/ai/eval/runs": { "get": { - "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", - "operationId": "aiEvalPromptSetsList", - "summary": "List eval prompt sets", + "description": "List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The `prompt_set_id` query parameter is required.", + "operationId": "aiEvalRunsList", + "summary": "List eval runs", "tags": [ "AI Eval" ], @@ -35780,42 +36699,40 @@ "true", "false" ], - "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", "example": "false" }, "required": false, - "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", "name": "archived", "in": "query" }, { "schema": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." + "type": "string", + "format": "uuid", + "description": "Required — the prompt set whose runs should be listed.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", - "name": "model_ids", + "required": true, + "description": "Required — the prompt set whose runs should be listed.", + "name": "prompt_set_id", "in": "query" } ], "responses": { "200": { - "description": "List of prompt sets, sorted alphabetically by name.", + "description": "List of runs for the prompt set.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsListResponse" + "$ref": "#/components/schemas/EvalRunsListResponse" } } } }, "400": { - "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", + "description": "Missing or invalid `prompt_set_id`.", "content": { "application/json": { "schema": { @@ -35835,7 +36752,7 @@ } }, "403": { - "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", + "description": "Insufficient permissions.", "content": { "application/json": { "schema": { @@ -35845,7 +36762,7 @@ } }, "404": { - "description": "No eval-accessible models for this caller.", + "description": "Prompt set not found.", "content": { "application/json": { "schema": { @@ -35857,9 +36774,9 @@ } }, "post": { - "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", - "operationId": "aiEvalPromptSetsCreate", - "summary": "Create an eval prompt set", + "description": "Create and start a new run against an existing prompt set. The run enqueues one agentic job per prompt and begins executing immediately. Returns the newly created run with its initial per-prompt result rows.", + "operationId": "aiEvalRunsCreate", + "summary": "Start an eval run", "tags": [ "AI Eval" ], @@ -35868,18 +36785,18 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsCreateBody" + "$ref": "#/components/schemas/EvalRunsCreateBody" } } } }, "responses": { "201": { - "description": "Prompt set created successfully.", + "description": "Run created and jobs enqueued.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" + "$ref": "#/components/schemas/EvalRunsCreateResponse" } } } @@ -35905,7 +36822,7 @@ } }, "403": { - "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", + "description": "Insufficient permissions. The caller must have at least the Querier role on the prompt set's model.", "content": { "application/json": { "schema": { @@ -35913,15 +36830,65 @@ } } } + }, + "404": { + "description": "The prompt set was not found, or `run_config.branch_id` does not match an existing branch in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "422": { + "description": "`run_config.branch_id` does not belong to the prompt set's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + }, + "429": { + "description": "Per-user active-run cap reached.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError429" + } + } + } + }, + "500": { + "description": "Run created and jobs enqueued, but it could not be re-read for the response. The run exists — list runs for the prompt set to find it rather than retrying, since a retry starts a duplicate run.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + }, + "503": { + "description": "AI eval is paused for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError503" + } + } + } } } } }, - "/api/v1/ai/eval/prompt-sets/{promptSetId}": { + "/api/v1/ai/eval/runs/{runId}": { "get": { - "description": "Get a single prompt set with all of its prompts.", - "operationId": "aiEvalPromptSetsGet", - "summary": "Get an eval prompt set", + "description": "Get an eval run with every per-prompt result row, including the underlying agentic job state and any scoring data.", + "operationId": "aiEvalRunsGet", + "summary": "Get an eval run", "tags": [ "AI Eval" ], @@ -35930,32 +36897,22 @@ "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", + "description": "The unique identifier of the eval run.", + "name": "runId", "in": "path" } ], "responses": { "200": { - "description": "Prompt set details.", + "description": "Run detail.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsGetResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` — must be a UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" + "$ref": "#/components/schemas/EvalRunsGetResponse" } } } @@ -35981,7 +36938,7 @@ } }, "404": { - "description": "Prompt set not found.", + "description": "Run not found.", "content": { "application/json": { "schema": { @@ -35992,10 +36949,10 @@ } } }, - "patch": { - "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list — existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", - "operationId": "aiEvalPromptSetsUpdate", - "summary": "Update an eval prompt set", + "delete": { + "description": "Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call is idempotent; archiving an already-terminal or already-archived run is a no-op.", + "operationId": "aiEvalRunsArchive", + "summary": "Archive an eval run", "tags": [ "AI Eval" ], @@ -36004,42 +36961,22 @@ "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", + "description": "The unique identifier of the eval run.", + "name": "runId", "in": "path" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" - } - } - } - }, "responses": { "200": { - "description": "Prompt set updated successfully.", + "description": "Run archived successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" + "$ref": "#/components/schemas/EvalRunsDeleteResponse" } } } @@ -36065,7 +37002,7 @@ } }, "404": { - "description": "Prompt set not found.", + "description": "Run not found.", "content": { "application/json": { "schema": { @@ -36074,22 +37011,24 @@ } } }, - "422": { - "description": "A `prompts[].id` in the request does not belong to this prompt set.", + "500": { + "description": "A still-running run may already be flipped to CANCELLED and archived even though the rest of the cascade failed — safe to retry.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalApiError422" + "$ref": "#/components/schemas/EvalApiError500" } } } } } - }, - "delete": { - "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent — retrying drains any remaining runs.", - "operationId": "aiEvalPromptSetsArchive", - "summary": "Archive an eval prompt set", + } + }, + "/api/v1/ai/eval/runs/{runId}/cancel": { + "post": { + "description": "Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived — the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use `/unarchive` to surface it in the default `archived=false` list again.", + "operationId": "aiEvalRunsCancel", + "summary": "Cancel an eval run", "tags": [ "AI Eval" ], @@ -36098,32 +37037,22 @@ "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", + "description": "The unique identifier of the eval run.", + "name": "runId", "in": "path" } ], "responses": { "200": { - "description": "Prompt set archived successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` — must be a UUID.", + "description": "Cancellation processed.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalApiError400" + "$ref": "#/components/schemas/EvalRunsCancelResponse" } } } @@ -36149,7 +37078,7 @@ } }, "404": { - "description": "Prompt set not found.", + "description": "Run not found.", "content": { "application/json": { "schema": { @@ -36159,7 +37088,7 @@ } }, "500": { - "description": "Archive committed but a run-cancellation failed; the set is already archived — safe to retry.", + "description": "The run was cancelled and archived, but could not be re-read for the response — safe to retry.", "content": { "application/json": { "schema": { @@ -36171,11 +37100,11 @@ } } }, - "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { + "/api/v1/ai/eval/runs/{runId}/unarchive": { "post": { - "description": "Restore an archived prompt set.", - "operationId": "aiEvalPromptSetsUnarchive", - "summary": "Restore an archived eval prompt set", + "description": "Restore an archived eval run.", + "operationId": "aiEvalRunsUnarchive", + "summary": "Restore an archived eval run", "tags": [ "AI Eval" ], @@ -36184,32 +37113,22 @@ "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", + "description": "The unique identifier of the eval run.", + "name": "runId", "in": "path" } ], "responses": { "200": { - "description": "Prompt set restored successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` — must be a UUID.", + "description": "Run restored successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalApiError400" + "$ref": "#/components/schemas/EvalRunsUnarchiveResponse" } } } @@ -36235,7 +37154,7 @@ } }, "404": { - "description": "Prompt set not found.", + "description": "Run not found.", "content": { "application/json": { "schema": { diff --git a/cmd/omni/openapi.json b/cmd/omni/openapi.json index 8697147..28c20c3 100644 --- a/cmd/omni/openapi.json +++ b/cmd/omni/openapi.json @@ -16015,9 +16015,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16120,9 +16117,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16265,9 +16259,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16344,9 +16335,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16425,9 +16413,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16543,9 +16528,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16618,9 +16600,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16710,9 +16689,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -16742,9 +16718,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -16816,9 +16789,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -16938,9 +16908,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -16999,9 +16966,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -17056,9 +17020,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -17158,9 +17119,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -17202,7 +17160,7 @@ ] } ], - "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.)." + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.). Visibility is determined by placement in the filter-bar container." }, "map": { "type": "object", @@ -17277,7 +17235,7 @@ "additionalProperties": { "$ref": "#/components/schemas/QueryPresentationPatchExternal" }, - "description": "Query presentations keyed by tab ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete. Capped at 48 entries per patch." + "description": "Query presentations keyed by tab ID. Shallow-merged by key — omitted keys are untouched; set to `null` to delete. Capped at 48 entries per patch. When the request carries no `containers` and the document has a dashboard layout, dashboard-eligible tiles added at new keys are auto-placed on the dashboard's first page (non-renderable types such as CSV / dataset / query-view / dbt tabs are stored but not placed), and containers created by auto-placement are removed when their tile is deleted — containers placed via an explicit `containers` write are left in the layout. When `containers` is present it fully defines the layout; on a workbook-only document (no layout yet) tiles are stored without placement." }, "order": { "type": "array", @@ -20156,9 +20114,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20261,9 +20216,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20406,9 +20358,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20485,9 +20434,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20566,9 +20512,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20684,9 +20627,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20759,9 +20699,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20851,9 +20788,6 @@ } ] }, - "hidden": { - "type": "boolean" - }, "label": { "type": "string" }, @@ -20883,9 +20817,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -20957,9 +20888,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21079,9 +21007,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21140,9 +21065,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21197,9 +21119,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21299,9 +21218,6 @@ "description": { "type": "string" }, - "hidden": { - "type": "boolean" - }, "id": { "type": "string" }, @@ -21343,7 +21259,7 @@ ] } ], - "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.)." + "description": "Filter or interactive control config. Discriminated by `type`: filter types (string, date, number, etc.) or control types (FIELD_SELECTION, PERIOD_OVER_PERIOD, etc.). Visibility is determined by placement in the filter-bar container." }, "map": { "type": "object", @@ -24194,7 +24110,7 @@ "$ref": "#/components/schemas/Containers" }, { - "description": "Container layout. When present, fully replaces the existing layout." + "description": "Container layout. When present, fully replaces the existing layout and disables automatic tile placement for the request." } ] }, @@ -24818,5573 +24734,6353 @@ "prompt_set" ] }, - "FoldersListResponse": { + "EvalRunsListResponse": { "type": "object", "properties": { - "pageInfo": { - "allOf": [ - { - "$ref": "#/components/schemas/PageInfo" - }, - { - "description": "Pagination information" - } - ] - }, - "records": { + "runs": { "type": "array", "items": { - "type": "object", - "properties": { - "_count": { - "type": "object", - "properties": { - "documents": { - "type": "number", - "description": "Number of documents in the folder" - }, - "favorites": { - "type": "number", - "description": "Number of users who have favorited this folder" - } - }, - "required": [ - "documents", - "favorites" - ], - "description": "Count statistics for the folder" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique folder identifier" - }, - "labels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels associated with the folder" - }, - "name": { - "type": "string", - "description": "Name of the folder", - "example": "My Reports" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the folder owner" - }, - "path": { - "type": "string", - "description": "Full path to the folder", - "example": "/shared/reports/my-reports" - }, - "url": { - "type": "string", - "description": "URL to view the folder in the Omni UI.", - "example": "https://org.omni.co/f/my-reports" - } - }, - "required": [ - "id", - "name", - "ownerId", - "path", - "url" - ] + "$ref": "#/components/schemas/EvalRunListItem" }, - "description": "List of folders" + "description": "Runs for the prompt set, newest first, filtered to those whose model the caller can access." } }, "required": [ - "pageInfo", - "records" + "runs" ] }, - "FoldersCreateResponse": { + "EvalRunListItem": { "type": "object", "properties": { + "branch_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", + "example": null + }, + "branch_name": { + "type": [ + "string", + "null" + ], + "description": "Display name for the branch, if `branch_id` is set.", + "example": null + }, + "completed_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run reached a terminal state.", + "example": null + }, + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description for the run.", + "example": null + }, "id": { "type": "string", "format": "uuid", - "description": "ID of the created folder" + "description": "Unique identifier for the run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, - "name": { - "type": "string", - "description": "Name of the created folder" + "is_archived": { + "type": "boolean", + "description": "Whether the run has been archived.", + "example": false }, - "ownerId": { + "model_id": { "type": "string", "format": "uuid", - "description": "User ID of the folder owner" + "description": "The shared model this run was executed against.", + "example": "880e8400-e29b-41d4-a716-446655440003" }, - "path": { + "prompt_set_id": { "type": "string", - "description": "Full path to the folder" + "format": "uuid", + "description": "The prompt set this run was created from.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "scope": { + "run_number": { + "type": "integer", + "description": "Sequential, per-prompt-set run number.", + "example": 3 + }, + "stats": { + "$ref": "#/components/schemas/EvalRunStats" + }, + "status": { "type": "string", "enum": [ - "organization", - "restricted" + "RUNNING", + "COMPLETE", + "CANCELLED" ], - "description": "Share scope of the folder" + "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", + "example": "RUNNING" } }, "required": [ + "branch_id", + "branch_name", + "completed_at", + "created_at", + "description", "id", - "name", - "ownerId", - "path", - "scope" + "is_archived", + "model_id", + "prompt_set_id", + "run_number", + "stats", + "status" ] }, - "FoldersCreateBody": { + "EvalRunStats": { "type": "object", "properties": { - "name": { - "type": "string", - "minLength": 1, - "description": "Name of the folder to create", - "example": "My New Folder" - }, - "parentFolderId": { - "type": "string", - "format": "uuid", - "description": "Parent folder ID (omit to create at root level)" - }, - "scope": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Share scope for the folder" + "terminal": { + "type": "integer", + "description": "Number of per-prompt jobs that have reached a terminal state (COMPLETE, FAILED, or CANCELLED).", + "example": 8 }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID to create the folder as (for org-scoped API keys only)" + "total": { + "type": "integer", + "description": "Total number of per-prompt jobs in the run.", + "example": 12 } }, "required": [ - "name" + "terminal", + "total" ] }, - "FoldersDeleteResponse": { + "EvalRunsCreateResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the folder was deleted successfully" + "job_count": { + "type": "integer", + "description": "Number of per-prompt agentic jobs created for this run (one per prompt that fanned out successfully). Enqueue onto the work queue happens after creation and is best-effort, so this count reflects jobs created, not necessarily those successfully enqueued.", + "example": 12 + }, + "run": { + "$ref": "#/components/schemas/EvalRunDetail" } }, "required": [ - "success" + "job_count", + "run" ] }, - "FoldersUpdateResponse": { + "EvalRunDetail": { "type": "object", "properties": { - "id": { - "type": "string", + "branch_id": { + "type": [ + "string", + "null" + ], "format": "uuid", - "description": "Folder ID" + "description": "Optional branch ID the run was executed against. Null when run against the main shared model.", + "example": null }, - "name": { - "type": "string", - "description": "Updated folder name" + "branch_name": { + "type": [ + "string", + "null" + ], + "description": "Display name for the branch, if `branch_id` is set.", + "example": null }, - "path": { - "type": "string", - "description": "Updated URL path segment for the folder (the folder's own segment only)" + "completed_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run reached a terminal state.", + "example": null + }, + "created_at": { + "type": [ + "string", + "null" + ], + "description": "ISO 8601 timestamp when the run was created.", + "example": "2025-01-15T10:00:00.000Z" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Optional human-readable description for the run.", + "example": null + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the run.", + "example": "660e8400-e29b-41d4-a716-446655440001" + }, + "is_archived": { + "type": "boolean", + "description": "Whether the run has been archived.", + "example": false + }, + "model_id": { + "type": "string", + "format": "uuid", + "description": "The shared model this run was executed against.", + "example": "880e8400-e29b-41d4-a716-446655440003" + }, + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set this run was created from.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EvalRunResult" + }, + "description": "Per-prompt results for this run, ordered by their creation order in the prompt set." + }, + "run_number": { + "type": "integer", + "description": "Sequential, per-prompt-set run number.", + "example": 3 + }, + "status": { + "type": "string", + "enum": [ + "RUNNING", + "COMPLETE", + "CANCELLED" + ], + "description": "Run-level lifecycle. Flips to a terminal state (COMPLETE or CANCELLED) exactly once.", + "example": "RUNNING" } }, "required": [ + "branch_id", + "branch_name", + "completed_at", + "created_at", + "description", "id", - "name", - "path" - ] + "is_archived", + "model_id", + "prompt_set_id", + "results", + "run_number", + "status" + ], + "description": "The newly created run with its initial results." }, - "FoldersUpdateBody": { + "EvalRunResult": { "type": "object", "properties": { - "name": { + "agentic_job": { + "$ref": "#/components/schemas/EvalRunResultAgenticJob" + }, + "cost": { + "type": [ + "number", + "null" + ], + "description": "Total LLM cost (USD) for this prompt, if available.", + "example": 0.0021 + }, + "error_reason": { + "type": [ + "string", + "null" + ], + "description": "Failure reason string for prompts whose underlying job failed.", + "example": null + }, + "expectation": { + "type": [ + "string", + "null" + ], + "description": "The prompt's expectation as of run creation (snapshotted, so later prompt edits don't change past runs), or null when none was set. The analysis judge scores the analysis against it.", + "example": "The top product by revenue should be Aniseed Syrup." + }, + "id": { "type": "string", - "minLength": 1, - "description": "New display name for the folder", - "example": "Q1 Reports" + "format": "uuid", + "description": "Unique identifier for the run result row.", + "example": "aa0e8400-e29b-41d4-a716-446655440005" }, - "path": { + "prompt": { "type": "string", - "minLength": 1, - "pattern": "^[a-zA-Z0-9-]+$", - "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", - "example": "q1-reports" + "description": "The prompt text that was evaluated.", + "example": "What are the top 5 products by revenue?" }, - "resolvePathConflict": { - "type": "boolean", - "default": false, - "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." + "score": { + "type": [ + "number", + "null" + ], + "description": "Numeric judge score for this prompt result, if scoring ran.", + "example": 0.9 + }, + "scoring_cost": { + "type": [ + "number", + "null" + ], + "description": "Total LLM cost (USD) for scoring this prompt result.", + "example": 0.0004 + }, + "timing_ms": { + "type": [ + "integer", + "null" + ], + "description": "Wall-clock duration of the underlying job in milliseconds.", + "example": 4321 } - } + }, + "required": [ + "agentic_job", + "cost", + "error_reason", + "expectation", + "id", + "prompt", + "score", + "scoring_cost", + "timing_ms" + ] }, - "FoldersGetPermissionsResponse": { + "EvalRunResultAgenticJob": { "type": "object", "properties": { - "permits": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoost": { - "type": "boolean", - "description": "Whether access boost is enabled for this permit" - }, - "role": { - "type": "string", - "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", - "example": "VIEWER" - }, - "userGroupId": { - "type": "string", - "description": "User group ID if this is a group permit" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "User ID if this is a user permit" - } - }, - "required": [ - "role" - ] - }, - "description": "List of permission permits for the folder" + "conversation_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Conversation the agentic job belongs to.", + "example": "770e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Agentic job identifier.", + "example": "990e8400-e29b-41d4-a716-446655440004" + }, + "state": { + "type": "string", + "enum": [ + "CANCELLED", + "COMPLETE", + "DELIVERING", + "EXECUTING", + "FAILED", + "QUEUED" + ], + "description": "Current state of the agentic job that ran this prompt.", + "example": "COMPLETE" } }, "required": [ - "permits" + "conversation_id", + "id", + "state" ] }, - "FoldersAddPermissionsResponse": { + "EvalApiError429": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were added successfully" + "detail": { + "type": "string", + "description": "Human-readable error message describing what went wrong.", + "example": "Too many active runs; wait for an in-flight run to finish" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 429 } }, "required": [ - "success" + "detail", + "status" ] }, - "FoldersAddPermissionsBody": { + "EvalApiError503": { "type": "object", "properties": { - "accessBoost": { - "type": "boolean", - "default": false, - "description": "Whether to grant access boost" - }, - "role": { + "detail": { "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" + "description": "Human-readable error message describing what went wrong.", + "example": "AI eval is paused for this organization" + }, + "status": { + "type": "integer", + "description": "HTTP status code of the error.", + "example": 503 + } + }, + "required": [ + "detail", + "status" + ] + }, + "EvalRunsCreateBody": { + "type": "object", + "properties": { + "description": { + "type": [ + "string", + "null" ], - "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", - "example": "VIEWER" + "maxLength": 1024, + "description": "Optional human-readable description for the run. Pass `null` to clear (or omit). Max 1024 characters.", + "example": "Re-running after switching to gpt-4o for query generation" }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to grant permission to" + "prompt_set_id": { + "type": "string", + "format": "uuid", + "description": "The prompt set to execute.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" + "run_config": { + "type": "object", + "properties": { + "branch_id": { + "type": "string", + "format": "uuid", + "description": "Optional branch ID to run against. Must be a branch of the prompt set's model.", + "example": "440e8400-e29b-41d4-a716-446655440006" + } }, - "default": [], - "description": "User IDs to grant permission to" + "description": "Per-run configuration. Optional — omit if no overrides." } }, "required": [ - "role" - ], - "additionalProperties": false + "prompt_set_id" + ] }, - "FoldersUpdatePermissionsResponse": { + "EvalRunsGetResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were updated successfully" + "run": { + "$ref": "#/components/schemas/EvalRunDetail" } }, "required": [ - "success" + "run" ] }, - "FoldersUpdatePermissionsBody": { + "EvalRunsDeleteResponse": { "type": "object", "properties": { - "accessBoost": { + "is_archived": { "type": "boolean", - "description": "Whether to grant access boost" - }, - "role": { - "type": "string", "enum": [ - "NO_ACCESS", - "VIEWER", - "EXPLORER", - "EDITOR", - "MANAGER" + true ], - "description": "New content role to assign" - }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to update permissions for" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to update permissions for" + "description": "Always `true` on success — the run has been archived." } }, - "additionalProperties": false + "required": [ + "is_archived" + ] }, - "FoldersRevokePermissionsResponse": { + "EvalRunsCancelResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the permissions were revoked successfully" + "cancelled": { + "type": "integer", + "description": "Number of per-prompt agentic jobs that were cancelled by this request.", + "example": 4 + }, + "run": { + "allOf": [ + { + "$ref": "#/components/schemas/EvalRunDetail" + }, + { + "description": "The cancelled run. `status: CANCELLED` and `is_archived: true` after this call." + } + ] + }, + "total": { + "type": "integer", + "description": "Total number of per-prompt jobs in the run.", + "example": 12 } }, "required": [ - "success" + "cancelled", + "run", + "total" ] }, - "FoldersRevokePermissionsBody": { + "EvalRunsUnarchiveResponse": { "type": "object", "properties": { - "userGroupIds": { - "type": "array", - "items": { - "type": "string" - }, - "default": [], - "description": "User group IDs to revoke permissions from" - }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "User IDs to revoke permissions from" + "is_archived": { + "type": "boolean", + "enum": [ + false + ], + "description": "Always `false` on success — the run has been unarchived." } }, - "additionalProperties": false + "required": [ + "is_archived" + ] }, - "LabelsListResponse": { + "FoldersListResponse": { "type": "object", "properties": { - "labels": { + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] + }, + "records": { "type": "array", "items": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" + "_count": { + "type": "object", + "properties": { + "documents": { + "type": "number", + "description": "Number of documents in the folder" + }, + "favorites": { + "type": "number", + "description": "Number of users who have favorited this folder" + } + }, + "required": [ + "documents", + "favorites" ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" + "description": "Count statistics for the folder" }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" + "id": { + "type": "string", + "format": "uuid", + "description": "Unique folder identifier" }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + "labels": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Labels associated with the folder" }, "name": { "type": "string", - "description": "Label name", - "example": "verified" + "description": "Name of the folder", + "example": "My Reports" }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" + "path": { + "type": "string", + "description": "Full path to the folder", + "example": "/shared/reports/my-reports" + }, + "url": { + "type": "string", + "description": "URL to view the folder in the Omni UI.", + "example": "https://org.omni.co/f/my-reports" } }, "required": [ - "color", - "description", - "homepage", + "id", "name", - "usage_count", - "verified" + "ownerId", + "path", + "url" ] }, - "description": "List of labels" + "description": "List of folders" } }, "required": [ - "labels" + "pageInfo", + "records" ] }, - "LabelsCreateResponse": { + "FoldersCreateResponse": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + "id": { + "type": "string", + "format": "uuid", + "description": "ID of the created folder" }, "name": { "type": "string", - "description": "Label name", - "example": "verified" + "description": "Name of the created folder" }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the folder owner" }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" + "path": { + "type": "string", + "description": "Full path to the folder" + }, + "scope": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope of the folder" } }, "required": [ - "color", - "description", - "homepage", + "id", "name", - "usage_count", - "verified" + "ownerId", + "path", + "scope" ] }, - "LabelsCreateBody": { + "FoldersCreateBody": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "default": null, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" + "name": { + "type": "string", + "minLength": 1, + "description": "Name of the folder to create", + "example": "My New Folder" }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "default": null, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "default": false, - "description": "Show label on homepage. Requires admin permissions." + "parentFolderId": { + "type": "string", + "format": "uuid", + "description": "Parent folder ID (omit to create at root level)" }, - "name": { + "scope": { "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" + "enum": [ + "organization", + "restricted" + ], + "description": "Share scope for the folder" }, - "verified": { - "type": "boolean", - "default": false, - "description": "Mark as verified label. Requires admin permissions." + "userId": { + "type": "string", + "format": "uuid", + "description": "User ID to create the folder as (for org-scoped API keys only)" } }, "required": [ "name" ] }, - "LabelsGetResponse": { + "FoldersDeleteResponse": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" - }, - "name": { - "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" - }, - "verified": { + "success": { "type": "boolean", - "description": "Whether label is verified" + "description": "Whether the folder was deleted successfully" } }, "required": [ - "color", - "description", - "homepage", - "name", - "usage_count", - "verified" + "success" ] }, - "LabelsUpdateResponse": { + "FoldersUpdateResponse": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Whether label is shown on homepage" + "id": { + "type": "string", + "format": "uuid", + "description": "Folder ID" }, "name": { "type": "string", - "description": "Label name", - "example": "verified" - }, - "usage_count": { - "type": "number", - "description": "Number of documents with this label" + "description": "Updated folder name" }, - "verified": { - "type": "boolean", - "description": "Whether label is verified" + "path": { + "type": "string", + "description": "Updated URL path segment for the folder (the folder's own segment only)" } }, "required": [ - "color", - "description", - "homepage", + "id", "name", - "usage_count", - "verified" + "path" ] }, - "LabelsUpdateBody": { + "FoldersUpdateBody": { "type": "object", "properties": { - "color": { - "type": [ - "string", - "null" - ], - "maxLength": 9, - "description": "Hex color for the label (e.g. #0366d6)", - "example": "#0366d6" - }, - "description": { - "type": [ - "string", - "null" - ], - "maxLength": 500, - "description": "Label description", - "example": "Important items that need attention" - }, - "homepage": { - "type": "boolean", - "description": "Show label on homepage. Requires admin permissions to modify." - }, "name": { "type": "string", - "minLength": 2, - "maxLength": 25, - "description": "Label name", - "example": "important" + "minLength": 1, + "description": "New display name for the folder", + "example": "Q1 Reports" }, - "verified": { + "path": { + "type": "string", + "minLength": 1, + "pattern": "^[a-zA-Z0-9-]+$", + "description": "New URL path segment for the folder (alphanumeric and dashes only). This is only the folder's own segment, not the full hierarchical path.", + "example": "q1-reports" + }, + "resolvePathConflict": { "type": "boolean", - "description": "Mark as verified label. Requires admin permissions to modify." + "default": false, + "description": "When true, automatically resolves path collisions with existing folders by appending a numeric suffix (e.g., my-path-1). When false (default), returns 409 Conflict if the path is already taken. Does not apply to reserved paths, which are always rejected with 400." } } }, - "ModelsListResponse": { + "FoldersGetPermissionsResponse": { "type": "object", "properties": { - "pageInfo": { - "allOf": [ - { - "$ref": "#/components/schemas/PageInfo" - }, - { - "description": "Pagination information" - } - ] - }, - "records": { + "permits": { "type": "array", "items": { "type": "object", "properties": { - "baseModelId": { - "type": [ - "string", - "null" - ], - "description": "Base model ID for branch/extension models" - }, - "branches": { - "type": "array", - "items": { - "type": "object", - "properties": { - "id": { - "type": "string", - "description": "Branch ID" - }, - "name": { - "type": "string", - "description": "Branch name" - } - }, - "required": [ - "id", - "name" - ] - }, - "description": "Active branches (if include=activeBranches)" - }, - "connectionId": { - "type": [ - "string", - "null" - ], - "description": "Connection ID" + "accessBoost": { + "type": "boolean", + "description": "Whether access boost is enabled for this permit" }, - "createdAt": { + "role": { "type": "string", - "description": "Creation timestamp" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Deletion timestamp" + "description": "Content role (e.g., VIEWER, EDITOR, MANAGER)", + "example": "VIEWER" }, - "id": { + "userGroupId": { "type": "string", - "description": "Model ID" - }, - "modelKind": { - "type": [ - "string", - "null" - ], - "description": "Model kind" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Model name" + "description": "User group ID if this is a group permit" }, - "updatedAt": { + "userId": { "type": "string", - "description": "Last update timestamp" + "format": "uuid", + "description": "User ID if this is a user permit" } }, "required": [ - "baseModelId", - "connectionId", - "createdAt", - "deletedAt", - "id", - "modelKind", - "name", - "updatedAt" + "role" ] }, - "description": "List of model records" + "description": "List of permission permits for the folder" } }, "required": [ - "pageInfo", - "records" + "permits" ] }, - "CreateModelSchemaBase": { + "FoldersAddPermissionsResponse": { "type": "object", "properties": { - "accessGrants": { - "type": "array", - "items": { - "type": "object", - "properties": { - "accessBoostable": { - "type": "boolean" - }, - "allowedValues": { - "type": "array", - "items": { - "type": "string" - } - }, - "codeComments": { - "type": "object", - "additionalProperties": { - "type": "string" - } - }, - "ignored": { - "type": "boolean" - }, - "name": { - "type": "string" - }, - "userAttribute": { - "type": "string" - } - }, - "required": [ - "accessBoostable", - "name" - ] - }, - "description": "Access grants for the model" - }, - "allowAsWorkbookBase": { + "success": { "type": "boolean", - "description": "Allow this model as a workbook base" - }, - "baseModelId": { - "type": "string", - "description": "Base model ID for extension or branch models" + "description": "Whether the permissions were added successfully" + } + }, + "required": [ + "success" + ] + }, + "FoldersAddPermissionsBody": { + "type": "object", + "properties": { + "accessBoost": { + "type": "boolean", + "default": false, + "description": "Whether to grant access boost" }, - "connectionId": { + "role": { "type": "string", - "description": "Connection ID for the model" - }, - "modelKind": { - "anyOf": [ - { - "type": "string", - "enum": [ - "SCHEMA" - ] - }, - { - "type": "string", - "enum": [ - "SHARED" - ] - }, - { - "type": "string", - "enum": [ - "SHARED_EXTENSION" - ] - }, - { - "type": "string", - "enum": [ - "BRANCH" - ] - } + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" ], - "default": "SCHEMA", - "description": "Kind of model to create" + "description": "Content role to assign (VIEWER, EDITOR, or MANAGER)", + "example": "VIEWER" }, - "modelName": { - "type": "string", - "description": "Name for the model" + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to grant permission to" }, - "usesIsolatedBranches": { - "type": "boolean", - "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to grant permission to" } }, "required": [ - "connectionId" - ] + "role" + ], + "additionalProperties": false }, - "ModelsUpdateResponse": { + "FoldersUpdatePermissionsResponse": { "type": "object", "properties": { - "model": { - "type": "object", - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Model ID" - }, - "name": { - "type": "string", - "description": "Updated model name" - } - }, - "required": [ - "id", - "name" - ], - "description": "Updated model details" - }, "success": { "type": "boolean", - "description": "Whether the operation succeeded" + "description": "Whether the permissions were updated successfully" } }, "required": [ - "model", "success" ] }, - "ModelsUpdateBody": { + "FoldersUpdatePermissionsBody": { "type": "object", "properties": { - "name": { + "accessBoost": { + "type": "boolean", + "description": "Whether to grant access boost" + }, + "role": { "type": "string", - "minLength": 1, - "description": "New name for the model", - "example": "My Renamed Model" + "enum": [ + "NO_ACCESS", + "VIEWER", + "EXPLORER", + "EDITOR", + "MANAGER" + ], + "description": "New content role to assign" + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string" + }, + "default": [], + "description": "User group IDs to update permissions for" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to update permissions for" } }, - "required": [ - "name" - ] + "additionalProperties": false }, - "JobsGetStatusResponse": { + "FoldersRevokePermissionsResponse": { "type": "object", "properties": { - "job_id": { - "type": "string", - "description": "The job ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "job_type": { - "type": "string", - "description": "The type of job (e.g., REFRESH_SCHEMA)", - "example": "REFRESH_SCHEMA" - }, - "status": { - "type": "string", - "enum": [ - "IN_PROGRESS", - "COMPLETED", - "FAILED" - ], - "description": "Current status of the job", - "example": "COMPLETED" + "success": { + "type": "boolean", + "description": "Whether the permissions were revoked successfully" } }, "required": [ - "job_id", - "job_type", - "status" + "success" ] }, - "ModelsGetSchemasResponse": { + "FoldersRevokePermissionsBody": { "type": "object", "properties": { - "schemas": { + "userGroupIds": { "type": "array", "items": { "type": "string" }, - "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" + "default": [], + "description": "User group IDs to revoke permissions from" + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "User IDs to revoke permissions from" } }, - "required": [ - "schemas" - ] + "additionalProperties": false }, - "ModelsGetViewResponse": { + "LabelsListResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "views": { + "labels": { "type": "array", "items": { "type": "object", "properties": { - "description": { - "type": "string", - "description": "View description" - }, - "fields": { - "type": "array", - "items": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Field name" - }, - "type": { - "type": "string", - "enum": [ - "dimension", - "measure", - "filter" - ], - "description": "Field type" - } - }, - "required": [ - "name", - "type" - ] - }, - "description": "Fields in the view" + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, - "hidden": { - "type": "boolean", - "description": "Whether the view is hidden" + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "label": { - "type": "string", - "description": "View label" + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" }, "name": { "type": "string", - "description": "View name" + "description": "Label name", + "example": "verified" + }, + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" } }, "required": [ - "fields", - "name" + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" ] }, - "description": "List of views" + "description": "List of labels" } }, "required": [ - "success", - "views" + "labels" ] }, - "ModelsUpdateViewBody": { + "LabelsCreateResponse": { "type": "object", "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the view" + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, "description": { - "type": "string", - "description": "View description" - }, - "format": { - "type": "string", - "description": "View format" + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "hidden": { + "homepage": { "type": "boolean", - "description": "Whether the view is hidden" + "description": "Whether label is shown on homepage" }, - "label": { + "name": { "type": "string", - "description": "View label" + "description": "Label name", + "example": "verified" }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the view" + "usage_count": { + "type": "number", + "description": "Number of documents with this label" + }, + "verified": { + "type": "boolean", + "description": "Whether label is verified" } - } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] }, - "ModelsUpdateFieldBody": { + "LabelsCreateBody": { "type": "object", "properties": { - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "allValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Deprecated: use sampleValues instead" - }, - "binBoundaries": { - "type": "array", - "items": { - "type": "number" - }, - "description": "Bin boundaries for binned fields" - }, - "binLabels": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Labels for bins" + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "default": null, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, "description": { - "type": "string", - "description": "Field description" + "type": [ + "string", + "null" + ], + "maxLength": 500, + "default": null, + "description": "Label description", + "example": "Important items that need attention" }, - "drillFields": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Drill-down fields" + "homepage": { + "type": "boolean", + "default": false, + "description": "Show label on homepage. Requires admin permissions." }, - "elseValue": { + "name": { "type": "string", - "description": "Else value for grouped fields" + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" }, - "filters": { - "type": "object", - "additionalProperties": {}, - "description": "Filters for the field" + "verified": { + "type": "boolean", + "default": false, + "description": "Mark as verified label. Requires admin permissions." + } + }, + "required": [ + "name" + ] + }, + "LabelsGetResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, - "format": { - "type": "string", - "description": "Field format" + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "groupFilters": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} - }, - "description": "Group filters" + "homepage": { + "type": "boolean", + "description": "Whether label is shown on homepage" }, - "groupLabel": { + "name": { "type": "string", - "description": "Group label" + "description": "Label name", + "example": "verified" }, - "groupNames": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Group names" + "usage_count": { + "type": "number", + "description": "Number of documents with this label" }, - "hidden": { + "verified": { "type": "boolean", - "description": "Whether the field is hidden" + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateResponse": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, - "ignored": { - "type": "boolean", - "description": "Whether the field is ignored" + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "isCalc": { + "homepage": { "type": "boolean", - "description": "Whether this is a calculation field" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "newFieldName": { - "type": "string", - "description": "New field name (for rename)" + "description": "Whether label is shown on homepage" }, - "newViewName": { + "name": { "type": "string", - "description": "New view name (for move)" + "description": "Label name", + "example": "verified" }, - "sampleValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Sample values for the field" + "usage_count": { + "type": "number", + "description": "Number of documents with this label" }, - "sql": { - "type": "string", - "description": "SQL expression for the field" + "verified": { + "type": "boolean", + "description": "Whether label is verified" + } + }, + "required": [ + "color", + "description", + "homepage", + "name", + "usage_count", + "verified" + ] + }, + "LabelsUpdateBody": { + "type": "object", + "properties": { + "color": { + "type": [ + "string", + "null" + ], + "maxLength": 9, + "description": "Hex color for the label (e.g. #0366d6)", + "example": "#0366d6" }, - "synonyms": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Synonyms for the field" + "description": { + "type": [ + "string", + "null" + ], + "maxLength": 500, + "description": "Label description", + "example": "Important items that need attention" }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" + "homepage": { + "type": "boolean", + "description": "Show label on homepage. Requires admin permissions to modify." }, - "topicContext": { + "name": { "type": "string", - "description": "Topic context for the field" + "minLength": 2, + "maxLength": 25, + "description": "Label name", + "example": "important" + }, + "verified": { + "type": "boolean", + "description": "Mark as verified label. Requires admin permissions to modify." } } }, - "ModelsListTopicsResponse": { + "ModelsListResponse": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" + "pageInfo": { + "allOf": [ + { + "$ref": "#/components/schemas/PageInfo" + }, + { + "description": "Pagination information" + } + ] }, - "topics": { + "records": { "type": "array", "items": { "type": "object", "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" + "baseModelId": { + "type": [ + "string", + "null" + ], + "description": "Base model ID for branch/extension models" }, - "description": { - "type": "string", - "description": "Topic description" + "branches": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Branch ID" + }, + "name": { + "type": "string", + "description": "Branch name" + } + }, + "required": [ + "id", + "name" + ] + }, + "description": "Active branches (if include=activeBranches)" }, - "group_label": { + "connectionId": { + "type": [ + "string", + "null" + ], + "description": "Connection ID" + }, + "createdAt": { "type": "string", - "description": "Group label" + "description": "Creation timestamp" }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Deletion timestamp" }, - "label": { + "id": { "type": "string", - "description": "Topic label" + "description": "Model ID" + }, + "modelKind": { + "type": [ + "string", + "null" + ], + "description": "Model kind" }, "name": { + "type": [ + "string", + "null" + ], + "description": "Model name" + }, + "updatedAt": { "type": "string", - "description": "Topic name" + "description": "Last update timestamp" } }, "required": [ - "base_view_name", - "name" + "baseModelId", + "connectionId", + "createdAt", + "deletedAt", + "id", + "modelKind", + "name", + "updatedAt" ] }, - "description": "List of topics" + "description": "List of model records" } }, "required": [ - "success", - "topics" + "pageInfo", + "records" ] }, - "ModelsGetTopicResponse": { + "CreateModelSchemaBase": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" - }, - "topic": { - "type": "object", - "properties": { - "base_view_name": { - "type": "string", - "description": "Base view name for the topic" - }, - "description": { - "type": "string", - "description": "Topic description" - }, - "group_label": { - "type": "string", - "description": "Group label" - }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" - }, - "label": { - "type": "string", - "description": "Topic label" - }, - "name": { - "type": "string", - "description": "Topic name" - }, - "relationships": { - "type": "array", - "items": { - "type": "object", - "additionalProperties": {} + "accessGrants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "accessBoostable": { + "type": "boolean" }, - "description": "Relationships for the topic" - }, - "views": { - "type": "array", - "items": { + "allowedValues": { + "type": "array", + "items": { + "type": "string" + } + }, + "codeComments": { "type": "object", - "additionalProperties": {} + "additionalProperties": { + "type": "string" + } }, - "description": "Views available in the topic" - } + "ignored": { + "type": "boolean" + }, + "name": { + "type": "string" + }, + "userAttribute": { + "type": "string" + } + }, + "required": [ + "accessBoostable", + "name" + ] }, - "required": [ - "base_view_name", - "name", - "relationships", - "views" - ], - "description": "Topic details with relationships and views" - } - }, - "required": [ - "success", - "topic" - ] - }, - "ModelsUpdateTopicBody": { - "type": "object", - "properties": { - "description": { + "description": "Access grants for the model" + }, + "allowAsWorkbookBase": { + "type": "boolean", + "description": "Allow this model as a workbook base" + }, + "baseModelId": { "type": "string", - "description": "Topic description" + "description": "Base model ID for extension or branch models" }, - "groupLabel": { + "connectionId": { "type": "string", - "description": "Group label for the topic" + "description": "Connection ID for the model" }, - "hidden": { - "type": "boolean", - "description": "Whether the topic is hidden" + "modelKind": { + "anyOf": [ + { + "type": "string", + "enum": [ + "SCHEMA" + ] + }, + { + "type": "string", + "enum": [ + "SHARED" + ] + }, + { + "type": "string", + "enum": [ + "SHARED_EXTENSION" + ] + }, + { + "type": "string", + "enum": [ + "BRANCH" + ] + } + ], + "default": "SCHEMA", + "description": "Kind of model to create" }, - "label": { + "modelName": { "type": "string", - "description": "Topic label" + "description": "Name for the model" }, - "newTopicName": { - "type": "string", - "description": "New topic name (for rename)" + "usesIsolatedBranches": { + "type": "boolean", + "description": "For SHARED_EXTENSION models, controls if branches are shown on extension model page instead of parent shared model" } - } + }, + "required": [ + "connectionId" + ] }, - "ModelsCreateFieldBody": { + "ModelsUpdateResponse": { "type": "object", "properties": { - "aggregateType": { - "type": "string", - "enum": [ - "AVERAGE", - "COUNT", - "COUNT_DISTINCT", - "LIST", - "MAX", - "MIN", - "SUM", - "MEDIAN", - "PERCENTILE", - "AVERAGE_DISTINCT_ON", - "SUM_DISTINCT_ON", - "MEDIAN_DISTINCT_ON", - "PERCENTILE_DISTINCT_ON", - "SEMANTIC_VIEW_AGG" + "model": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Model ID" + }, + "name": { + "type": "string", + "description": "Updated model name" + } + }, + "required": [ + "id", + "name" ], - "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", - "example": "SUM" - }, - "aiContext": { - "type": "string", - "description": "AI context for the field" - }, - "description": { - "type": "string", - "description": "Field description" - }, - "fieldName": { - "type": "string", - "description": "Field name", - "example": "total_revenue" - }, - "format": { - "type": "string", - "description": "Field format" + "description": "Updated model details" }, - "hidden": { + "success": { "type": "boolean", - "description": "Whether the field is hidden" - }, - "label": { - "type": "string", - "description": "Field label" - }, - "sql": { - "type": "string", - "description": "SQL expression for the field" - }, - "tags": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Tags for the field" - }, - "topicContext": { - "type": "string", - "description": "Topic context for topic-scoped fields" - }, - "viewName": { + "description": "Whether the operation succeeded" + } + }, + "required": [ + "model", + "success" + ] + }, + "ModelsUpdateBody": { + "type": "object", + "properties": { + "name": { "type": "string", - "description": "View to add the field to", - "example": "orders" + "minLength": 1, + "description": "New name for the model", + "example": "My Renamed Model" } }, "required": [ - "fieldName", - "viewName" - ], - "additionalProperties": false + "name" + ] }, - "ModelsRefreshResponse": { + "JobsGetStatusResponse": { "type": "object", "properties": { - "jobId": { + "job_id": { "type": "string", - "description": "Job ID for the refresh operation" + "description": "The job ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "modelId": { + "job_type": { "type": "string", - "description": "Model ID being refreshed" + "description": "The type of job (e.g., REFRESH_SCHEMA)", + "example": "REFRESH_SCHEMA" }, "status": { "type": "string", "enum": [ - "running", - "completed", - "failed" + "IN_PROGRESS", + "COMPLETED", + "FAILED" ], - "description": "Current status of the refresh" + "description": "Current status of the job", + "example": "COMPLETED" } }, "required": [ - "jobId", - "modelId", + "job_id", + "job_type", "status" ] }, - "ModelsValidateResponse": { + "ModelsGetSchemasResponse": { "type": "object", "properties": { - "issues": { + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sorted list of all available schema names (catalog-scoped if applicable, e.g. warehouse.reporting)" + } + }, + "required": [ + "schemas" + ] + }, + "ModelsGetViewResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "views": { "type": "array", "items": { "type": "object", "properties": { - "field": { + "description": { "type": "string", - "description": "Field name with the issue" + "description": "View description" }, - "message": { - "type": "string", - "description": "Validation issue message" + "fields": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Field name" + }, + "type": { + "type": "string", + "enum": [ + "dimension", + "measure", + "filter" + ], + "description": "Field type" + } + }, + "required": [ + "name", + "type" + ] + }, + "description": "Fields in the view" }, - "severity": { + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { "type": "string", - "enum": [ - "error", - "warning" - ], - "description": "Issue severity" + "description": "View label" }, - "view": { + "name": { "type": "string", - "description": "View name with the issue" + "description": "View name" } }, "required": [ - "message", - "severity" + "fields", + "name" ] }, - "description": "List of validation issues" - }, - "valid": { - "type": "boolean", - "description": "Whether the model is valid" + "description": "List of views" } }, "required": [ - "issues", - "valid" + "success", + "views" ] }, - "ModelsMigrateBody": { + "ModelsUpdateViewBody": { "type": "object", "properties": { - "branchName": { + "aiContext": { "type": "string", - "description": "Branch name for the target model" + "description": "AI context for the view" }, - "commitMessage": { + "description": { "type": "string", - "description": "Commit message for git sync" - }, - "deleteViewsAndTopicsMissingFromSource": { - "type": "boolean", - "default": true, - "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead — useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." + "description": "View description" }, - "gitRef": { + "format": { "type": "string", - "description": "Git reference" + "description": "View format" }, - "targetModelId": { + "hidden": { + "type": "boolean", + "description": "Whether the view is hidden" + }, + "label": { "type": "string", - "format": "uuid", - "description": "Target model ID to migrate to" - } - }, - "required": [ - "targetModelId" - ] - }, - "ModelsDbtExposuresResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + "description": "View label" }, - "records": { + "tags": { "type": "array", "items": { - "$ref": "#/components/schemas/DbtExposureWithMeta" - } + "type": "string" + }, + "description": "Tags for the view" } - }, - "required": [ - "pageInfo", - "records" - ] + } }, - "DbtExposureWithMeta": { + "ModelsUpdateFieldBody": { "type": "object", "properties": { - "dashboard_identifier": { + "aiContext": { "type": "string", - "description": "Identifier of the dashboard that generated this exposure" + "description": "AI context for the field" }, - "deduplication_name": { - "type": "string", - "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." + "allValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Deprecated: use sampleValues instead" }, - "exposure": { - "$ref": "#/components/schemas/DbtExposure" - } - }, - "required": [ - "dashboard_identifier", - "deduplication_name", - "exposure" - ] - }, - "DbtExposure": { - "type": "object", - "properties": { - "depends_on": { + "binBoundaries": { + "type": "array", + "items": { + "type": "number" + }, + "description": "Bin boundaries for binned fields" + }, + "binLabels": { "type": "array", "items": { "type": "string" }, - "description": "List of dbt model references (e.g. ref('model_name'))", - "example": [ - "ref('orders')", - "ref('customers')" - ] + "description": "Labels for bins" }, - "label": { + "description": { "type": "string", - "description": "Original dashboard name" + "description": "Field description" }, - "name": { + "drillFields": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Drill-down fields" + }, + "elseValue": { "type": "string", - "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", - "example": "my_dashboard" + "description": "Else value for grouped fields" }, - "owner": { - "$ref": "#/components/schemas/DbtExposureOwner" + "filters": { + "type": "object", + "additionalProperties": {}, + "description": "Filters for the field" }, - "type": { + "format": { "type": "string", - "enum": [ - "dashboard", - "notebook", - "analysis", - "ml", - "application" - ], - "description": "Type of the exposure", - "example": "dashboard" + "description": "Field format" }, - "url": { - "type": "string", - "description": "URL of the dashboard" - } - }, - "required": [ - "depends_on", - "name", - "owner", - "type" - ], - "description": "The dbt exposure for this dashboard." - }, - "DbtExposureOwner": { - "type": "object", - "properties": { - "email": { - "type": "string", - "description": "Email of the dashboard owner" + "groupFilters": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Group filters" }, - "name": { - "type": "string", - "description": "Name of the dashboard owner" - } - }, - "required": [ - "email", - "name" - ] - }, - "ModelsBranchDbtBody": { - "type": "object", - "properties": { - "dbt_environment_id": { + "groupLabel": { "type": "string", - "format": "uuid", - "description": "ID of the dbt environment to activate on this branch", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Group label" }, - "dbt_git_branch": { - "type": "string", - "description": "Git branch to associate with the dbt environment", - "example": "feature/new-metrics" - } - }, - "required": [ - "dbt_environment_id" - ] - }, - "ModelsMergeBranchResponse": { - "type": "object", - "properties": { - "failed_drafts_count": { - "type": "number", - "description": "Number of drafts that failed to publish" + "groupNames": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Group names" }, - "git_synced": { + "hidden": { "type": "boolean", - "description": "Whether git was synced" + "description": "Whether the field is hidden" }, - "published_drafts_count": { - "type": "number", - "description": "Number of drafts published" + "ignored": { + "type": "boolean", + "description": "Whether the field is ignored" }, - "success": { + "isCalc": { "type": "boolean", - "description": "Whether the merge succeeded" - } - }, - "required": [ - "failed_drafts_count", - "git_synced", - "published_drafts_count", - "success" - ] - }, - "ModelsMergeBranchBody": { - "type": "object", - "properties": { - "commit_message": { + "description": "Whether this is a calculation field" + }, + "label": { "type": "string", - "description": "Custom commit message for git sync" + "description": "Field label" }, - "delete_branch": { - "type": "boolean", - "default": false, - "description": "Delete the branch after merging" + "newFieldName": { + "type": "string", + "description": "New field name (for rename)" }, - "force_override_git_settings": { - "type": "boolean", - "default": false, - "description": "Override PR-required or git-follower settings" + "newViewName": { + "type": "string", + "description": "New view name (for move)" }, - "publish_drafts": { - "type": "boolean", - "default": true, - "description": "Publish branch-attached drafts" - } - } - }, - "ModelsCommitResponse": { - "type": "object", - "properties": { - "did_sync": { - "type": "boolean", - "description": "Whether a sync operation was performed against git" + "sampleValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Sample values for the field" }, - "git_sha": { - "type": [ - "string", - "null" - ], - "description": "The git SHA of the commit that was pushed (null if no commit was needed)" + "sql": { + "type": "string", + "description": "SQL expression for the field" }, - "in_sync": { - "type": "boolean", - "description": "Whether the branch is in sync with git after the operation" + "synonyms": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Synonyms for the field" }, - "pr_url": { - "type": [ - "string", - "null" - ], - "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" + }, + "topicContext": { + "type": "string", + "description": "Topic context for the field" } - }, - "required": [ - "did_sync", - "git_sha", - "in_sync", - "pr_url" - ] + } }, - "ModelsCommitBody": { + "ModelsListTopicsResponse": { "type": "object", "properties": { - "allow_branch_exists": { + "success": { "type": "boolean", - "default": true, - "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", - "example": true - }, - "branch_id": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to commit.", - "example": "123e4567-e89b-12d3-a456-426614174001" - }, - "commit_message": { - "type": "string", - "minLength": 1, - "description": "Commit message for the git commit.", - "example": "Add new orders view" + "description": "Whether the operation succeeded" }, - "require_branch_exists": { - "type": "boolean", - "default": false, - "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", - "example": false + "topics": { + "type": "array", + "items": { + "type": "object", + "properties": { + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" + }, + "description": { + "type": "string", + "description": "Topic description" + }, + "group_label": { + "type": "string", + "description": "Group label" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + } + }, + "required": [ + "base_view_name", + "name" + ] + }, + "description": "List of topics" } }, "required": [ - "branch_id", - "commit_message" + "success", + "topics" ] }, - "ModelsCacheResetResponse": { + "ModelsGetTopicResponse": { "type": "object", "properties": { - "cache_reset": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" + }, + "topic": { "type": "object", "properties": { - "created_at": { - "type": [ - "string", - "null" - ], - "description": "Creation timestamp" + "base_view_name": { + "type": "string", + "description": "Base view name for the topic" }, - "model_id": { + "description": { "type": "string", - "description": "Model ID" + "description": "Topic description" }, - "policy_name": { + "group_label": { "type": "string", - "description": "Cache policy name" + "description": "Group label" }, - "reset_at": { - "type": [ - "string", - "null" - ], - "description": "Reset timestamp" + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" }, - "updated_at": { - "type": [ - "string", - "null" - ], - "description": "Last update timestamp" + "label": { + "type": "string", + "description": "Topic label" + }, + "name": { + "type": "string", + "description": "Topic name" + }, + "relationships": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Relationships for the topic" + }, + "views": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + }, + "description": "Views available in the topic" } }, "required": [ - "created_at", - "model_id", - "policy_name", - "reset_at", - "updated_at" + "base_view_name", + "name", + "relationships", + "views" ], - "description": "Cache reset details" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded" + "description": "Topic details with relationships and views" } }, "required": [ - "cache_reset", - "success" + "success", + "topic" ] }, - "ModelsCacheResetBody": { + "ModelsUpdateTopicBody": { "type": "object", "properties": { - "resetAt": { + "description": { "type": "string", - "description": "ISO-8601 timestamp for when to reset the cache", - "example": "2024-01-15T12:00:00Z" + "description": "Topic description" + }, + "groupLabel": { + "type": "string", + "description": "Group label for the topic" + }, + "hidden": { + "type": "boolean", + "description": "Whether the topic is hidden" + }, + "label": { + "type": "string", + "description": "Topic label" + }, + "newTopicName": { + "type": "string", + "description": "New topic name (for rename)" } } }, - "ModelsGitGetResponse": { + "ModelsCreateFieldBody": { "type": "object", "properties": { - "authMethod": { + "aggregateType": { "type": "string", "enum": [ - "ssh", - "https_token" + "AVERAGE", + "COUNT", + "COUNT_DISTINCT", + "LIST", + "MAX", + "MIN", + "SUM", + "MEDIAN", + "PERCENTILE", + "AVERAGE_DISTINCT_ON", + "SUM_DISTINCT_ON", + "MEDIAN_DISTINCT_ON", + "PERCENTILE_DISTINCT_ON", + "SEMANTIC_VIEW_AGG" ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" + "description": "Aggregate type for measures. Setting this property promotes the field to a measure (written under `measures:`); omit it to create a dimension (written under `dimensions:`). Values must be uppercase canonical names.", + "example": "SUM" }, - "baseBranch": { + "aiContext": { "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false + "description": "AI context for the field" }, - "cloneUrl": { + "description": { "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false + "description": "Field description" }, - "gitServiceProvider": { + "fieldName": { "type": "string", - "description": "The git provider type", - "example": "github" + "description": "Field name", + "example": "total_revenue" }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" + "format": { + "type": "string", + "description": "Field format" }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." + "hidden": { + "type": "boolean", + "description": "Whether the field is hidden" }, - "requirePullRequest": { + "label": { "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" + "description": "Field label" }, - "sshUrl": { + "sql": { "type": "string", - "deprecated": true, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository." + "description": "SQL expression for the field" }, - "webUrl": { - "type": [ - "string", - "null" - ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Tags for the field" }, - "webhookSecret": { + "topicContext": { "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + "description": "Topic context for topic-scoped fields" }, - "webhookUrl": { + "viewName": { "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." + "description": "View to add the field to", + "example": "orders" } }, "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" - ] + "fieldName", + "viewName" + ], + "additionalProperties": false }, - "ModelsGitCreateResponse": { + "ModelsRefreshResponse": { "type": "object", "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false - }, - "cloneUrl": { + "jobId": { "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false + "description": "Job ID for the refresh operation" }, - "gitServiceProvider": { + "modelId": { "type": "string", - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" - }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." + "description": "Model ID being refreshed" }, - "requirePullRequest": { + "status": { "type": "string", "enum": [ - "always", - "users-only", - "never" - ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" - }, - "sshUrl": { - "type": "string", - "deprecated": true, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository." - }, - "webUrl": { - "type": [ - "string", - "null" + "running", + "completed", + "failed" ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" - }, - "webhookSecret": { - "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" - }, - "webhookUrl": { - "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." + "description": "Current status of the refresh" } }, "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" + "jobId", + "modelId", + "status" ] }, - "ModelsGitCreateBody": { + "ModelsValidateResponse": { "type": "object", "properties": { - "authMethod": { - "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "default": "ssh", - "description": "Authentication method. \"ssh\" for deploy key (default), \"https_token\" for deploy token/PAT.", - "example": "ssh" - }, - "baseBranch": { - "type": "string", - "default": "main", - "description": "The target branch for Omni pull requests. Defaults to \"main\"", - "example": "main" - }, - "branchPerPullRequest": { - "type": "boolean", - "default": false, - "description": "If true, all pull requests will create a branch in Omni. Defaults to false", - "example": false - }, - "cloneUrl": { - "type": "string", - "minLength": 1, - "description": "Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth.", - "example": "git@github.com:org/repo.git" + "issues": { + "type": "array", + "items": { + "type": "object", + "properties": { + "field": { + "type": "string", + "description": "Field name with the issue" + }, + "message": { + "type": "string", + "description": "Validation issue message" + }, + "severity": { + "type": "string", + "enum": [ + "error", + "warning" + ], + "description": "Issue severity" + }, + "view": { + "type": "string", + "description": "View name with the issue" + } + }, + "required": [ + "message", + "severity" + ] + }, + "description": "List of validation issues" }, - "gitFollower": { + "valid": { "type": "boolean", - "default": false, - "description": "If true, the shared model will be read-only. Defaults to false", - "example": false - }, - "gitServiceProvider": { + "description": "Whether the model is valid" + } + }, + "required": [ + "issues", + "valid" + ] + }, + "ModelsMigrateBody": { + "type": "object", + "properties": { + "branchName": { "type": "string", - "enum": [ - "github", - "gitlab", - "azure_devops", - "bitbucket", - "bitbucket_datacenter", - "auto" - ], - "default": "auto", - "description": "The git provider type. Use \"auto\" for automatic detection. Defaults to \"auto\"", - "example": "auto" + "description": "Branch name for the target model" }, - "modelPath": { + "commitMessage": { "type": "string", - "description": "Path to model files in the repository. Defaults to omni/. Use a plain name (e.g., \"my_model\") for omni/my_model, or a leading slash for a custom path (e.g., \"/bi/models/sales\")", - "example": "my_model" + "description": "Commit message for git sync" }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "default": "never", - "description": "Controls when pull requests are required. Defaults to \"never\"", - "example": "never" + "deleteViewsAndTopicsMissingFromSource": { + "type": "boolean", + "default": true, + "description": "When true (default), views and topics in the target model that are missing from the migrated source are deleted (the source is treated as the complete model). When false, they are kept (inherited) instead — useful when the source git ref may be missing objects that exist in omni but not in git, e.g. a newly synced schema." }, - "sshUrl": { + "gitRef": { "type": "string", - "minLength": 1, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", - "example": "git@github.com:org/repo.git", - "deprecated": true + "description": "Git reference" }, - "token": { + "targetModelId": { "type": "string", - "maxLength": 1000, - "pattern": "^[a-zA-Z0-9_\\-.]+$", - "description": "HTTPS token for authentication (deploy token value, PAT, etc.). Required when authMethod is \"https_token\"." + "format": "uuid", + "description": "Target model ID to migrate to" + } + }, + "required": [ + "targetModelId" + ] + }, + "ModelsDbtExposuresResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" }, - "webUrl": { - "type": "string", - "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", - "example": "https://github.com/org/repo" + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DbtExposureWithMeta" + } } - } + }, + "required": [ + "pageInfo", + "records" + ] }, - "ModelsGitUpdateResponse": { + "DbtExposureWithMeta": { "type": "object", "properties": { - "authMethod": { + "dashboard_identifier": { "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", - "example": "ssh" + "description": "Identifier of the dashboard that generated this exposure" }, - "baseBranch": { + "deduplication_name": { "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" + "description": "A unique name for this exposure. Use this instead of exposure.name to avoid duplicate names, or use it as a fallback when exposure.name collides with another exposure." }, - "branchPerPullRequest": { - "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", - "example": false + "exposure": { + "$ref": "#/components/schemas/DbtExposure" + } + }, + "required": [ + "dashboard_identifier", + "deduplication_name", + "exposure" + ] + }, + "DbtExposure": { + "type": "object", + "properties": { + "depends_on": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of dbt model references (e.g. ref('model_name'))", + "example": [ + "ref('orders')", + "ref('customers')" + ] }, - "cloneUrl": { + "label": { "type": "string", - "description": "Clone URL of the git repository (SSH or HTTPS)", - "example": "git@github.com:org/repo.git" - }, - "gitFollower": { - "type": "boolean", - "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", - "example": false + "description": "Original dashboard name" }, - "gitServiceProvider": { + "name": { "type": "string", - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": [ - "string", - "null" - ], - "description": "Path to model files in the repository", - "example": "omni/my_model" + "description": "Sanitized exposure name. May contain duplicates across exposures; use deduplication_name for a guaranteed-unique alternative.", + "example": "my_dashboard" }, - "publicKey": { - "type": [ - "string", - "null" - ], - "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", - "example": "ssh-ed25519 AAAA..." + "owner": { + "$ref": "#/components/schemas/DbtExposureOwner" }, - "requirePullRequest": { + "type": { "type": "string", "enum": [ - "always", - "users-only", - "never" + "dashboard", + "notebook", + "analysis", + "ml", + "application" ], - "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", - "example": "users-only" + "description": "Type of the exposure", + "example": "dashboard" }, - "sshUrl": { + "url": { "type": "string", - "deprecated": true, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository." - }, - "webUrl": { - "type": [ - "string", - "null" - ], - "description": "Custom web URL for the git repository, or null if not set", - "example": "https://github.com/org/repo" - }, - "webhookSecret": { + "description": "URL of the dashboard" + } + }, + "required": [ + "depends_on", + "name", + "owner", + "type" + ], + "description": "The dbt exposure for this dashboard." + }, + "DbtExposureOwner": { + "type": "object", + "properties": { + "email": { "type": "string", - "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" + "description": "Email of the dashboard owner" }, - "webhookUrl": { + "name": { "type": "string", - "description": "Webhook URL to configure in your git provider", - "example": "https://app.omni.co/api/webhooks/model/..." + "description": "Name of the dashboard owner" } }, "required": [ - "authMethod", - "baseBranch", - "branchPerPullRequest", - "cloneUrl", - "gitFollower", - "gitServiceProvider", - "modelPath", - "publicKey", - "requirePullRequest", - "sshUrl", - "webUrl", - "webhookUrl" + "email", + "name" ] }, - "ModelsGitUpdateBody": { + "ModelsBranchDbtBody": { "type": "object", "properties": { - "authMethod": { + "dbt_environment_id": { "type": "string", - "enum": [ - "ssh", - "https_token" - ], - "description": "Authentication method to change to.", - "example": "ssh" + "format": "uuid", + "description": "ID of the dbt environment to activate on this branch", + "example": "123e4567-e89b-12d3-a456-426614174000" }, - "baseBranch": { + "dbt_git_branch": { "type": "string", - "description": "The target branch for Omni pull requests", - "example": "main" + "description": "Git branch to associate with the dbt environment", + "example": "feature/new-metrics" + } + }, + "required": [ + "dbt_environment_id" + ] + }, + "ModelsMergeBranchResponse": { + "type": "object", + "properties": { + "failed_drafts_count": { + "type": "number", + "description": "Number of drafts that failed to publish" }, - "branchPerPullRequest": { + "git_synced": { "type": "boolean", - "description": "If true, all pull requests will create a branch in Omni", - "example": false + "description": "Whether git was synced" }, - "cloneUrl": { - "type": "string", - "minLength": 1, - "description": "Clone URL of the git repository (SSH or HTTPS).", - "example": "git@github.com:org/repo.git" + "published_drafts_count": { + "type": "number", + "description": "Number of drafts published" }, - "gitFollower": { + "success": { "type": "boolean", - "description": "If true, the shared model will be read-only", - "example": false - }, - "gitServiceProvider": { - "type": "string", - "enum": [ - "github", - "gitlab", - "azure_devops", - "bitbucket", - "bitbucket_datacenter", - "auto" - ], - "description": "The git provider type", - "example": "github" - }, - "modelPath": { - "type": "string", - "description": "Path to model files in the repository", - "example": "my_model" - }, - "requirePullRequest": { - "type": "string", - "enum": [ - "always", - "users-only", - "never" - ], - "description": "Controls when pull requests are required", - "example": "users-only" - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", - "example": "git@github.com:org/repo.git", - "deprecated": true - }, - "token": { - "type": "string", - "maxLength": 1000, - "pattern": "^[a-zA-Z0-9_\\-.]+$", - "description": "HTTPS token for authentication (deploy token value, PAT, etc.)." - }, - "webUrl": { - "type": "string", - "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", - "example": "https://github.com/org/repo" + "description": "Whether the merge succeeded" } - } + }, + "required": [ + "failed_drafts_count", + "git_synced", + "published_drafts_count", + "success" + ] }, - "ModelsGitDeleteResponse": { + "ModelsMergeBranchBody": { "type": "object", "properties": { - "message": { + "commit_message": { "type": "string", - "description": "Success message", - "example": "Git repository unlinked successfully" + "description": "Custom commit message for git sync" }, - "success": { + "delete_branch": { "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + "default": false, + "description": "Delete the branch after merging" + }, + "force_override_git_settings": { + "type": "boolean", + "default": false, + "description": "Override PR-required or git-follower settings" + }, + "publish_drafts": { + "type": "boolean", + "default": true, + "description": "Publish branch-attached drafts" } - }, - "required": [ - "message", - "success" - ] + } }, - "ModelsGitSyncResponse": { + "ModelsCommitResponse": { "type": "object", "properties": { - "didSync": { + "did_sync": { "type": "boolean", - "description": "Whether a sync operation was performed" + "description": "Whether a sync operation was performed against git" }, - "gitSha": { + "git_sha": { "type": [ "string", "null" ], - "description": "The git SHA after the sync operation" + "description": "The git SHA of the commit that was pushed (null if no commit was needed)" }, - "inSync": { + "in_sync": { "type": "boolean", - "description": "Whether the model is currently in sync with git" + "description": "Whether the branch is in sync with git after the operation" }, - "message": { - "type": "string", - "description": "Human-readable message about the sync status" + "pr_url": { + "type": [ + "string", + "null" + ], + "description": "The URL of the pull request (or PR creation page for newly-created PRs). May be null when the underlying git provider is not recognized." } }, "required": [ - "didSync", - "gitSha", - "inSync", - "message" + "did_sync", + "git_sha", + "in_sync", + "pr_url" ] }, - "ModelsGitSyncBody": { + "ModelsCommitBody": { "type": "object", "properties": { - "commitMessage": { + "allow_branch_exists": { + "type": "boolean", + "default": true, + "description": "If true (default), the commit succeeds whether the git branch already exists or not. If false, the request fails when the git branch already exists — use this to ensure only new pull requests are created. Cannot be false when require_branch_exists is true.", + "example": true + }, + "branch_id": { "type": "string", - "description": "Optional commit message for the git sync operation", - "example": "Update model schema" + "format": "uuid", + "description": "UUID of the branch to commit.", + "example": "123e4567-e89b-12d3-a456-426614174001" + }, + "commit_message": { + "type": "string", + "minLength": 1, + "description": "Commit message for the git commit.", + "example": "Add new orders view" + }, + "require_branch_exists": { + "type": "boolean", + "default": false, + "description": "If true, the request fails when the git branch does not already exist — use this to ensure only existing pull requests are updated. Defaults to false. Cannot be true when allow_branch_exists is false.", + "example": false } - } + }, + "required": [ + "branch_id", + "commit_message" + ] }, - "ModelsContentValidatorGetResponse": { + "ModelsCacheResetResponse": { "type": "object", "properties": { - "branch": { - "type": [ - "object", - "null" - ], + "cache_reset": { + "type": "object", "properties": { - "id": { - "type": "string", - "description": "Branch UUID" - }, - "name": { + "created_at": { + "type": [ + "string", + "null" + ], + "description": "Creation timestamp" + }, + "model_id": { "type": "string", - "description": "Branch name" + "description": "Model ID" + }, + "policy_name": { + "type": "string", + "description": "Cache policy name" + }, + "reset_at": { + "type": [ + "string", + "null" + ], + "description": "Reset timestamp" + }, + "updated_at": { + "type": [ + "string", + "null" + ], + "description": "Last update timestamp" } }, "required": [ - "id", - "name" + "created_at", + "model_id", + "policy_name", + "reset_at", + "updated_at" ], - "description": "Branch info (present if branch_id was specified)" - }, - "content": { - "type": "array", - "items": {}, - "description": "Documents with their validation results" + "description": "Cache reset details" }, - "model_id": { - "type": "string", - "description": "Model UUID" + "success": { + "type": "boolean", + "description": "Whether the operation succeeded" } }, "required": [ - "branch", - "content", - "model_id" + "cache_reset", + "success" ] }, - "ContentFilterMode": { - "type": "string", - "enum": [ - "ALL", - "WITH_ISSUES", - "NO_ISSUES" - ], - "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors." - }, - "ModelsContentValidatorReplaceResponse": { + "ModelsCacheResetBody": { "type": "object", "properties": { - "replaced_dashboard_filters_count": { - "type": "integer", - "description": "Number of dashboard filters replaced" - }, - "replaced_documents_count": { - "type": "integer", - "description": "Number of documents modified" - }, - "replaced_queries_count": { - "type": "integer", - "description": "Number of queries replaced" - }, - "replaced_workbook_models_count": { - "type": "integer", - "description": "Number of workbook models replaced" - }, - "skipped_pr_required_count": { - "type": "integer", - "description": "Number of documents skipped due to pull request requirements" + "resetAt": { + "type": "string", + "description": "ISO-8601 timestamp for when to reset the cache", + "example": "2024-01-15T12:00:00Z" } - }, - "required": [ - "replaced_dashboard_filters_count", - "replaced_documents_count", - "replaced_queries_count", - "replaced_workbook_models_count", - "skipped_pr_required_count" - ] + } }, - "ModelsContentValidatorReplaceBody": { + "ModelsGitGetResponse": { "type": "object", "properties": { - "branch_id": { + "authMethod": { "type": "string", - "description": "Optional branch ID" + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" }, - "creator_id": { + "baseBranch": { "type": "string", - "format": "uuid", - "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." + "description": "The target branch for Omni pull requests", + "example": "main" }, - "find": { - "type": "string", - "minLength": 1, - "description": "The string to find" + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false }, - "find_or_replace_type": { + "cloneUrl": { "type": "string", - "enum": [ - "FIELD", - "TOPIC", - "VIEW" - ], - "description": "Type of find/replace operation." - }, - "folder_paths": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Restrict replacement to documents in matching folder paths (prefix match). Documents with no folder are excluded unless \"\" is specified." + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" }, - "include_personal_folders": { + "gitFollower": { "type": "boolean", - "default": false, - "description": "Whether to include personal folders" + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false }, - "labels": { + "gitServiceProvider": { "type": "string", - "description": "Comma-separated label names to scope replacement. Unknown labels return 400." + "description": "The git provider type", + "example": "github" }, - "only_in_workbook_id": { + "modelPath": { + "type": [ + "string", + "null" + ], + "description": "Path to model files in the repository", + "example": "omni/my_model" + }, + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { "type": "string", - "description": "Optional workbook ID to limit the replace scope" + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" }, - "replacement": { + "sshUrl": { "type": "string", - "minLength": 1, - "description": "The replacement string" - } - }, - "required": [ - "find", - "find_or_replace_type", - "replacement" - ] - }, - "ModelYamlResponse": { - "type": "object", - "properties": { - "checksums": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "Checksums for each file" + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." }, - "files": { - "type": "object", - "additionalProperties": { - "type": "string" - }, - "description": "YAML content for each file" + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" }, - "version": { - "type": "number", - "description": "Model version number" + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" }, - "viewNames": { - "type": "object", - "additionalProperties": {}, - "description": "View name mappings" + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." } }, "required": [ - "files", - "version" + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" ] }, - "ModelYamlCreateRequestBody": { + "ModelsGitCreateResponse": { "type": "object", "properties": { - "branchId": { + "authMethod": { "type": "string", - "format": "uuid", - "description": "Branch ID for branch-aware operations" + "enum": [ + "ssh", + "https_token" + ], + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" }, - "fileName": { + "baseBranch": { "type": "string", - "minLength": 1, - "description": "File name to create or update" - }, - "mode": { - "type": "string", - "enum": [ - "combined", - "extension", - "staged", - "merged", - "fully-resolved" - ], - "default": "combined", - "description": "IDE mode for YAML operations" + "description": "The target branch for Omni pull requests", + "example": "main" }, - "commitMessage": { - "type": "string", - "description": "Commit message for git sync" + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false }, - "fetchedAtMillis": { - "type": "number", - "description": "Timestamp when the file was fetched" + "cloneUrl": { + "type": "string", + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" }, - "fullyResolved": { + "gitFollower": { "type": "boolean", - "default": false, - "description": "Treat the posted YAML as fully resolved (with the extends chain expanded). Only valid with mode=combined." + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false }, - "previousChecksum": { + "gitServiceProvider": { "type": "string", - "description": "Previous checksum for conflict detection" + "description": "The git provider type", + "example": "github" }, - "yaml": { - "type": "string", - "description": "YAML content for the file" - } - }, - "required": [ - "fileName", - "yaml" - ], - "additionalProperties": false - }, - "AiAgentActionsResponse": { - "type": "object", - "properties": { - "records": { - "type": "array", - "items": { - "$ref": "#/components/schemas/AiAgentAction" - }, - "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." - } - }, - "required": [ - "records" - ] - }, - "AiAgentAction": { - "type": "object", - "properties": { - "kind": { - "type": "string", - "enum": [ - "sample", - "skill" + "modelPath": { + "type": [ + "string", + "null" ], - "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", - "example": "skill" + "description": "Path to model files in the repository", + "example": "omni/my_model" }, - "label": { + "publicKey": { + "type": [ + "string", + "null" + ], + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." + }, + "requirePullRequest": { "type": "string", - "description": "Short, human-readable name for the action — chip text in client UIs and the visible \"prompt\" on the answer card.", - "example": "Revenue trends" + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" }, - "prompt": { + "sshUrl": { "type": "string", - "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", - "example": "Skill:\nShow me the recent revenue trends grouped by month…" - } - }, - "required": [ - "kind", - "label", - "prompt" - ] - }, - "QueryRunResponse": { - "type": "object", - "properties": { - "completedQueries": { - "type": "array", - "items": {}, - "description": "Queries that completed synchronously with their results." + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." }, - "jobIds": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for results.", - "example": [ - "job_abc123", - "job_def456" - ] + "webUrl": { + "type": [ + "string", + "null" + ], + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" }, - "plan": { - "description": "Query execution plan (only present if planOnly is true)." - } - } - }, - "QueryTimeoutResponse": { - "type": "object", - "properties": { - "detail": { + "webhookSecret": { "type": "string", - "description": "Error message indicating the query timed out.", - "example": "Query timed out" - }, - "remaining_job_ids": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Job IDs for queries that have not yet completed. Use /api/v1/query/wait to poll for results." + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" }, - "timed_out": { - "type": "boolean", - "enum": [ - true - ], - "description": "Always true for timeout responses.", - "example": true + "webhookUrl": { + "type": "string", + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." } }, "required": [ - "detail", - "timed_out" + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" ] }, - "QueryRunBody": { + "ModelsGitCreateBody": { "type": "object", "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "Optional model branch to run the query against. Must belong to the same shared model as the query. When omitted, the query runs against the shared model. Takes precedence over the legacy `?branch_id=` URL query parameter.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "cache": { + "authMethod": { "type": "string", "enum": [ - "disabled", - "normal", - "refresh", - "refresh_all" + "ssh", + "https_token" ], - "description": "Cache policy for query execution. Controls whether to use cached results.", - "example": "normal" + "default": "ssh", + "description": "Authentication method. \"ssh\" for deploy key (default), \"https_token\" for deploy token/PAT.", + "example": "ssh" }, - "formatResults": { - "type": "boolean", - "description": "Whether to format result values (e.g., apply number formatting). Only valid when resultType is specified." + "baseBranch": { + "type": "string", + "default": "main", + "description": "The target branch for Omni pull requests. Defaults to \"main\"", + "example": "main" }, - "planOnly": { + "branchPerPullRequest": { "type": "boolean", "default": false, - "description": "If true, returns only the query execution plan without running the query." + "description": "If true, all pull requests will create a branch in Omni. Defaults to false", + "example": false }, - "query": { - "description": "The semantic query definition including fields, filters, sorts, and other query parameters." + "cloneUrl": { + "type": "string", + "minLength": 1, + "description": "Clone URL of the git repository. SSH (git@...) for deploy key auth, HTTPS (https://...) for token auth.", + "example": "git@github.com:org/repo.git" }, - "resultType": { + "gitFollower": { + "type": "boolean", + "default": false, + "description": "If true, the shared model will be read-only. Defaults to false", + "example": false + }, + "gitServiceProvider": { "type": "string", "enum": [ - "csv", - "json", - "xlsx" + "github", + "gitlab", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "auto" ], - "description": "Output format for the results. If not specified, returns base64-encoded Arrow format." + "default": "auto", + "description": "The git provider type. Use \"auto\" for automatic detection. Defaults to \"auto\"", + "example": "auto" }, - "userId": { + "modelPath": { "type": "string", - "format": "uuid", - "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter — this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - } - }, - "QueryWaitResponse": { - "type": "object", - "properties": { - "results": { - "type": "array", - "items": {}, - "description": "Array of completed query results. Each result contains the query data or an error." - } - }, - "required": [ - "results" - ] - }, - "SchedulesListItem": { - "type": "object", - "properties": { - "alert": { - "type": "object", - "properties": { - "conditionQueryName": { - "type": [ - "string", - "null" - ], - "description": "Name of the query used for alert condition" - }, - "conditionType": { - "type": "string", - "description": "Type of alert condition: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" - } - }, - "required": [ - "conditionQueryName", - "conditionType" - ], - "description": "Alert configuration (only present for alert-type schedules)" + "description": "Path to model files in the repository. Defaults to omni/. Use a plain name (e.g., \"my_model\") for omni/my_model, or a leading slash for a custom path (e.g., \"/bi/models/sales\")", + "example": "my_model" }, - "content": { + "requirePullRequest": { "type": "string", - "description": "Content type: dashboard or tile", - "example": "dashboard" + "enum": [ + "always", + "users-only", + "never" + ], + "default": "never", + "description": "Controls when pull requests are required. Defaults to \"never\"", + "example": "never" }, - "dashboardName": { + "sshUrl": { "type": "string", - "description": "Name of the dashboard", - "example": "Weekly Sales Report" + "minLength": 1, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", + "example": "git@github.com:org/repo.git", + "deprecated": true }, - "destinationType": { + "token": { "type": "string", - "description": "Delivery destination type: email, slack, webhook, sftp, s3, google_sheets", - "example": "email" + "maxLength": 1000, + "pattern": "^[a-zA-Z0-9_\\-.]+$", + "description": "HTTPS token for authentication (deploy token value, PAT, etc.). Required when authMethod is \"https_token\"." }, - "disabledAt": { - "type": [ - "string", - "null" + "webUrl": { + "type": "string", + "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", + "example": "https://github.com/org/repo" + } + } + }, + "ModelsGitUpdateResponse": { + "type": "object", + "properties": { + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" ], - "format": "date-time", - "description": "Timestamp when the schedule was paused (null if active)" + "description": "Authentication method. \"ssh\" for deploy key, \"https_token\" for deploy token/PAT.", + "example": "ssh" }, - "format": { + "baseBranch": { "type": "string", - "description": "Output format: pdf, png, csv, xlsx, json, link_only", - "example": "pdf" + "description": "The target branch for Omni pull requests", + "example": "main" }, - "id": { + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni, even those created outside of the tool", + "example": false + }, + "cloneUrl": { "type": "string", - "format": "uuid", - "description": "Unique identifier for the schedule" + "description": "Clone URL of the git repository (SSH or HTTPS)", + "example": "git@github.com:org/repo.git" }, - "identifier": { + "gitFollower": { + "type": "boolean", + "description": "If true, the shared model is read-only and can only be updated by merging pull requests to the base branch", + "example": false + }, + "gitServiceProvider": { "type": "string", - "description": "Dashboard identifier", - "example": "12db1a0a" + "description": "The git provider type", + "example": "github" }, - "lastCompletedAt": { + "modelPath": { "type": [ "string", "null" ], - "format": "date-time", - "description": "Timestamp of last completed delivery" + "description": "Path to model files in the repository", + "example": "omni/my_model" }, - "lastStatus": { + "publicKey": { "type": [ "string", "null" ], - "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" - }, - "name": { - "type": "string", - "description": "Name of the schedule", - "example": "Weekly Sales Report" - }, - "ownerId": { - "type": "string", - "format": "uuid", - "description": "User ID of the schedule owner" + "description": "SSH public key for repository access (deploy key). Null for HTTPS token auth.", + "example": "ssh-ed25519 AAAA..." }, - "ownerName": { + "requirePullRequest": { "type": "string", - "description": "Display name of the schedule owner", - "example": "John Doe" - }, - "recipientCount": { - "type": "number", - "description": "Number of recipients (-1 for non-email destinations)", - "example": 5 + "enum": [ + "always", + "users-only", + "never" + ], + "description": "When pull requests are required: \"always\" for all changes, \"users-only\" for user-initiated changes only, \"never\" for direct commits.", + "example": "users-only" }, - "schedule": { + "sshUrl": { "type": "string", - "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", - "example": "0 9 ? * MON *" - }, - "slackRecipientType": { - "type": [ - "string", - "null" - ], - "description": "Slack recipient type: Channel or Users (null for non-Slack)" + "deprecated": true, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository." }, - "systemDisabledAt": { + "webUrl": { "type": [ "string", "null" ], - "format": "date-time", - "description": "Timestamp when system disabled the schedule (null if not system-disabled)" + "description": "Custom web URL for the git repository, or null if not set", + "example": "https://github.com/org/repo" }, - "systemDisabledReason": { - "type": [ - "string", - "null" - ], - "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + "webhookSecret": { + "type": "string", + "description": "Webhook secret for signature verification. Only included if requested via ?include=webhookSecret" }, - "timezone": { + "webhookUrl": { "type": "string", - "description": "IANA timezone for the schedule", - "example": "America/New_York" + "description": "Webhook URL to configure in your git provider", + "example": "https://app.omni.co/api/webhooks/model/..." } }, "required": [ - "content", - "dashboardName", - "destinationType", - "disabledAt", - "format", - "id", - "identifier", - "lastCompletedAt", - "lastStatus", - "name", - "ownerId", - "ownerName", - "recipientCount", - "schedule", - "slackRecipientType", - "systemDisabledAt", - "systemDisabledReason", - "timezone" + "authMethod", + "baseBranch", + "branchPerPullRequest", + "cloneUrl", + "gitFollower", + "gitServiceProvider", + "modelPath", + "publicKey", + "requirePullRequest", + "sshUrl", + "webUrl", + "webhookUrl" ] }, - "SchedulesGetResponse": { + "ModelsGitUpdateBody": { "type": "object", "properties": { - "conditionQueryMapKey": { - "type": [ - "string", - "null" - ], - "description": "Query key used for alert condition (null for standard schedules)" - }, - "conditionType": { - "type": [ - "string", - "null" + "authMethod": { + "type": "string", + "enum": [ + "ssh", + "https_token" ], - "description": "Alert condition type: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + "description": "Authentication method to change to.", + "example": "ssh" }, - "createdAt": { + "baseBranch": { "type": "string", - "format": "date-time", - "description": "Creation timestamp" + "description": "The target branch for Omni pull requests", + "example": "main" }, - "destinations": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchedulesGetDestination" - }, - "description": "Delivery destination configurations" + "branchPerPullRequest": { + "type": "boolean", + "description": "If true, all pull requests will create a branch in Omni", + "example": false }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp when the schedule was paused (null if active)" - }, - "entityId": { + "cloneUrl": { "type": "string", - "description": "ID of the associated dashboard" + "minLength": 1, + "description": "Clone URL of the git repository (SSH or HTTPS).", + "example": "git@github.com:org/repo.git" }, - "fanOut": { + "gitFollower": { "type": "boolean", - "description": "Whether personalized fan-out delivery is enabled", + "description": "If true, the shared model will be read-only", "example": false }, - "filterConfig": { - "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." - }, - "id": { + "gitServiceProvider": { "type": "string", - "format": "uuid", - "description": "Schedule UUID", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "killJobsOnFailure": { - "type": "boolean", - "description": "Whether to stop the job if any queries fail", - "example": false - }, - "metadata": { - "description": "Schedule metadata including format options and delivery settings" + "enum": [ + "github", + "gitlab", + "azure_devops", + "bitbucket", + "bitbucket_datacenter", + "auto" + ], + "description": "The git provider type", + "example": "github" }, - "name": { + "modelPath": { "type": "string", - "description": "Schedule name", - "example": "Weekly Sales Report" + "description": "Path to model files in the repository", + "example": "my_model" }, - "organizationId": { + "requirePullRequest": { "type": "string", - "format": "uuid", - "description": "Organization UUID" + "enum": [ + "always", + "users-only", + "never" + ], + "description": "Controls when pull requests are required", + "example": "users-only" }, - "owner": { - "type": "object", - "properties": { - "name": { - "type": "string", - "description": "Schedule owner name" - } - }, - "required": [ - "name" - ] + "sshUrl": { + "type": "string", + "minLength": 1, + "description": "Deprecated — use cloneUrl. Clone URL of the git repository.", + "example": "git@github.com:org/repo.git", + "deprecated": true }, - "ownerId": { + "token": { "type": "string", - "format": "uuid", - "description": "User ID of the schedule owner" + "maxLength": 1000, + "pattern": "^[a-zA-Z0-9_\\-.]+$", + "description": "HTTPS token for authentication (deploy token value, PAT, etc.)." }, - "schedule": { + "webUrl": { "type": "string", - "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", - "example": "0 9 ? * MON *" + "description": "Custom web URL for the git repository. Use when the clone URL goes through a tunnel/VPC and differs from the inferred HTTPS address", + "example": "https://github.com/org/repo" + } + } + }, + "ModelsGitDeleteResponse": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "Git repository unlinked successfully" }, - "systemDisabledAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp when the system disabled the schedule" + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ] + }, + "ModelsGitSyncResponse": { + "type": "object", + "properties": { + "didSync": { + "type": "boolean", + "description": "Whether a sync operation was performed" }, - "systemDisabledReason": { + "gitSha": { "type": [ "string", "null" ], - "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + "description": "The git SHA after the sync operation" }, - "timezone": { - "type": "string", - "description": "IANA timezone for the schedule", - "example": "America/New_York" + "inSync": { + "type": "boolean", + "description": "Whether the model is currently in sync with git" }, - "updatedAt": { + "message": { "type": "string", - "format": "date-time", - "description": "Last update timestamp" + "description": "Human-readable message about the sync status" } }, "required": [ - "conditionQueryMapKey", - "conditionType", - "createdAt", - "destinations", - "disabledAt", - "entityId", - "fanOut", - "id", - "killJobsOnFailure", - "name", - "organizationId", - "owner", - "ownerId", - "schedule", - "systemDisabledAt", - "systemDisabledReason", - "timezone", - "updatedAt" + "didSync", + "gitSha", + "inSync", + "message" ] }, - "SchedulesGetDestination": { + "ModelsGitSyncBody": { "type": "object", "properties": { - "format": { - "type": "string", - "description": "Output format: pdf, png, csv, xlsx, json, link_only", - "example": "pdf" - }, - "id": { + "commitMessage": { "type": "string", - "format": "uuid", - "description": "Destination UUID" - }, - "lastCompletedAt": { - "type": [ - "string", - "null" - ], - "format": "date-time", - "description": "Timestamp of last completed delivery" - }, - "lastStatus": { + "description": "Optional commit message for the git sync operation", + "example": "Update model schema" + } + } + }, + "ModelsContentValidatorGetResponse": { + "type": "object", + "properties": { + "branch": { "type": [ - "string", + "object", "null" ], - "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" - }, - "metadata": { - "description": "Destination-specific configuration (type, recipients, credentials, etc.)" - }, - "recipients": { - "type": "array", - "items": { - "$ref": "#/components/schemas/SchedulesGetRecipient" + "properties": { + "id": { + "type": "string", + "description": "Branch UUID" + }, + "name": { + "type": "string", + "description": "Branch name" + } }, - "description": "Individual email recipients" + "required": [ + "id", + "name" + ], + "description": "Branch info (present if branch_id was specified)" }, - "userGroupRecipients": { + "content": { "type": "array", "items": {}, - "description": "User group recipients" + "description": "Documents with their validation results" + }, + "model_id": { + "type": "string", + "description": "Model UUID" } }, "required": [ - "format", - "id", - "lastCompletedAt", - "lastStatus", - "recipients", - "userGroupRecipients" + "branch", + "content", + "model_id" ] }, - "SchedulesGetRecipient": { + "ContentFilterMode": { + "type": "string", + "enum": [ + "ALL", + "WITH_ISSUES", + "NO_ISSUES" + ], + "description": "Filter documents by issue status. ALL (default) returns all documents with at least one query. WITH_ISSUES returns only documents with at least one query issue, dashboard filter issue, or document error. NO_ISSUES returns only documents with zero issues and no document errors." + }, + "ModelsContentValidatorReplaceResponse": { "type": "object", "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "Recipient ID" + "replaced_dashboard_filters_count": { + "type": "integer", + "description": "Number of dashboard filters replaced" }, - "membership": { - "type": "object", - "properties": { - "user": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Recipient email" - }, - "name": { - "type": [ - "string", - "null" - ], - "description": "Recipient name" - } - }, - "required": [ - "email", - "name" - ] - } - }, - "required": [ - "user" - ] + "replaced_documents_count": { + "type": "integer", + "description": "Number of documents modified" }, - "membershipId": { - "type": "string", - "format": "uuid", - "description": "Membership ID" + "replaced_queries_count": { + "type": "integer", + "description": "Number of queries replaced" + }, + "replaced_workbook_models_count": { + "type": "integer", + "description": "Number of workbook models replaced" + }, + "skipped_pr_required_count": { + "type": "integer", + "description": "Number of documents skipped due to pull request requirements" } }, "required": [ - "id", - "membership", - "membershipId" + "replaced_dashboard_filters_count", + "replaced_documents_count", + "replaced_queries_count", + "replaced_workbook_models_count", + "skipped_pr_required_count" ] }, - "SchedulesRecipientsGetResponse": { + "ModelsContentValidatorReplaceBody": { "type": "object", "properties": { - "recipients": { - "type": "array", - "items": { - "$ref": "#/components/schemas/EmailRecipient" - }, - "description": "List of individual recipients (for email destinations)." + "branch_id": { + "type": "string", + "description": "Optional branch ID" }, - "type": { + "creator_id": { + "type": "string", + "format": "uuid", + "description": "Restrict replacement to documents created by this user (user ID). Unknown IDs return 400." + }, + "find": { + "type": "string", + "minLength": 1, + "description": "The string to find" + }, + "find_or_replace_type": { "type": "string", "enum": [ - "email", - "google_sheets", - "s3", - "sftp", - "slack", - "webhook" + "FIELD", + "TOPIC", + "VIEW" ], - "description": "The schedule's destination type.", - "example": "email" + "description": "Type of find/replace operation." }, - "userGroupRecipients": { + "folder_paths": { "type": "array", "items": { - "$ref": "#/components/schemas/UserGroupRecipient" + "type": "string" }, - "description": "List of user group recipients (for email destinations)." + "description": "Restrict replacement to documents in matching folder paths (prefix match). Documents with no folder are excluded unless \"\" is specified." + }, + "include_personal_folders": { + "type": "boolean", + "default": false, + "description": "Whether to include personal folders" + }, + "labels": { + "type": "string", + "description": "Comma-separated label names to scope replacement. Unknown labels return 400." + }, + "only_in_workbook_id": { + "type": "string", + "description": "Optional workbook ID to limit the replace scope" + }, + "replacement": { + "type": "string", + "minLength": 1, + "description": "The replacement string" } }, "required": [ - "type" + "find", + "find_or_replace_type", + "replacement" ] }, - "EmailRecipient": { + "ModelYamlResponse": { "type": "object", "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Recipient's email address.", - "example": "user@example.com" + "checksums": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "Checksums for each file" }, - "id": { - "type": "string", - "description": "Unique identifier for the recipient." + "files": { + "type": "object", + "additionalProperties": { + "type": "string" + }, + "description": "YAML content for each file" }, - "name": { - "type": "string", - "description": "Recipient's display name.", - "example": "John Doe" + "version": { + "type": "number", + "description": "Model version number" + }, + "viewNames": { + "type": "object", + "additionalProperties": {}, + "description": "View name mappings" } }, "required": [ - "email", - "id", - "name" + "files", + "version" ] }, - "UserGroupRecipient": { + "ModelYamlCreateRequestBody": { "type": "object", "properties": { - "id": { + "branchId": { "type": "string", - "description": "User group ID." + "format": "uuid", + "description": "Branch ID for branch-aware operations" }, - "name": { + "fileName": { "type": "string", - "description": "User group name.", - "example": "Sales Team" + "minLength": 1, + "description": "File name to create or update" }, - "recipients": { + "mode": { + "type": "string", + "enum": [ + "combined", + "extension", + "staged", + "merged", + "fully-resolved" + ], + "default": "combined", + "description": "IDE mode for YAML operations" + }, + "commitMessage": { + "type": "string", + "description": "Commit message for git sync" + }, + "fetchedAtMillis": { + "type": "number", + "description": "Timestamp when the file was fetched" + }, + "fullyResolved": { + "type": "boolean", + "default": false, + "description": "Treat the posted YAML as fully resolved (with the extends chain expanded). Only valid with mode=combined." + }, + "previousChecksum": { + "type": "string", + "description": "Previous checksum for conflict detection" + }, + "yaml": { + "type": "string", + "description": "YAML content for the file" + } + }, + "required": [ + "fileName", + "yaml" + ], + "additionalProperties": false + }, + "AiAgentActionsResponse": { + "type": "object", + "properties": { + "records": { "type": "array", "items": { - "$ref": "#/components/schemas/EmailRecipient" + "$ref": "#/components/schemas/AiAgentAction" }, - "description": "List of recipients in the user group." + "description": "AI agent actions in display order: sample queries first, then skills. Topic-level entries follow model-level ones, and skills are deduped by id with topic skills winning over model skills." } }, "required": [ - "id", - "name", - "recipients" + "records" ] }, - "SchedulesAddRecipientsResponse": { + "AiAgentAction": { "type": "object", "properties": { - "addedGroupRecipientsCount": { - "type": "number", - "description": "Number of user group recipients added.", - "example": 1 + "kind": { + "type": "string", + "enum": [ + "sample", + "skill" + ], + "description": "Source of the entry: `sample` for `sample_queries` (model- or topic-level) and `skill` for `skills` (model- or topic-level).", + "example": "skill" }, - "addedRecipientsCount": { - "type": "number", - "description": "Number of individual recipients added.", - "example": 2 + "label": { + "type": "string", + "description": "Short, human-readable name for the action — chip text in client UIs and the visible \"prompt\" on the answer card.", + "example": "Revenue trends" }, - "success": { - "type": "boolean", - "description": "Whether the operation was successful.", - "example": true + "prompt": { + "type": "string", + "description": "Submit this string verbatim as the `prompt` on `POST /api/v1/ai/jobs`. For sample queries this is the raw prompt; for skills it is a pre-formatted wrapper around the skill's input.", + "example": "Skill:\nShow me the recent revenue trends grouped by month…" } }, "required": [ - "addedGroupRecipientsCount", - "addedRecipientsCount", - "success" + "kind", + "label", + "prompt" ] }, - "SchedulesAddRecipientsBody": { + "QueryRunResponse": { "type": "object", "properties": { - "emails": { + "completedQueries": { "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of email addresses to add as recipients.", - "example": [ - "user@example.com" - ] + "items": {}, + "description": "Queries that completed synchronously with their results." }, - "userGroupIds": { + "jobIds": { "type": "array", "items": { - "type": "string", - "format": "uuid" + "type": "string" }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to add as recipients.", + "description": "Job IDs for queries running asynchronously. Use /api/v1/query/wait to poll for results.", "example": [ - "123e4567-e89b-12d3-a456-426614174000" + "job_abc123", + "job_def456" ] }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user UUIDs to add as recipients. Use the List users and List embed users endpoints to retrieve user IDs.", - "example": [ - "987fcdeb-51a2-43d7-9b56-254415f67890" - ] + "plan": { + "description": "Query execution plan (only present if planOnly is true)." } } }, - "SchedulesRemoveRecipientsResponse": { + "QueryTimeoutResponse": { "type": "object", "properties": { - "removedGroupRecipientsCount": { - "type": "number", - "description": "Number of user group recipients removed.", - "example": 1 + "detail": { + "type": "string", + "description": "Error message indicating the query timed out.", + "example": "Query timed out" }, - "removedRecipientsCount": { - "type": "number", - "description": "Number of individual recipients removed.", - "example": 2 + "remaining_job_ids": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Job IDs for queries that have not yet completed. Use /api/v1/query/wait to poll for results." }, - "success": { + "timed_out": { "type": "boolean", - "description": "Whether the operation was successful.", + "enum": [ + true + ], + "description": "Always true for timeout responses.", "example": true } }, "required": [ - "removedGroupRecipientsCount", - "removedRecipientsCount", - "success" + "detail", + "timed_out" ] }, - "SchedulesRemoveRecipientsBody": { + "QueryRunBody": { "type": "object", "properties": { - "emails": { - "type": "array", - "items": { - "type": "string", - "format": "email" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of recipient email addresses to remove from the scheduled task.", - "example": [ - "user@example.com" - ] + "branchId": { + "type": "string", + "format": "uuid", + "description": "Optional model branch to run the query against. Must belong to the same shared model as the query. When omitted, the query runs against the shared model. Takes precedence over the legacy `?branch_id=` URL query parameter.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "userGroupIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to remove as recipients.", - "example": [ - "123e4567-e89b-12d3-a456-426614174000" - ] + "cache": { + "type": "string", + "enum": [ + "disabled", + "normal", + "refresh", + "refresh_all" + ], + "description": "Cache policy for query execution. Controls whether to use cached results.", + "example": "normal" }, - "userIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "default": [], - "description": "At least one email, userId, or userGroupId must be provided. Array of recipient user UUIDs to remove from the scheduled task. Use the List users and List embed users endpoints to retrieve user IDs.", - "example": [ - "987fcdeb-51a2-43d7-9b56-254415f67890" - ] + "formatResults": { + "type": "boolean", + "description": "Whether to format result values (e.g., apply number formatting). Only valid when resultType is specified." + }, + "planOnly": { + "type": "boolean", + "default": false, + "description": "If true, returns only the query execution plan without running the query." + }, + "query": { + "description": "The semantic query definition including fields, filters, sorts, and other query parameters." + }, + "resultType": { + "type": "string", + "enum": [ + "csv", + "json", + "xlsx" + ], + "description": "Output format for the results. If not specified, returns base64-encoded Arrow format." + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "Alternate location for the `?userId=` query parameter. Prefer the query parameter — this body field exists for backwards compatibility. Supplying both forms results in a 400. Only valid for org-scoped API keys; when set, the user's attributes are applied for row-level security and connection-environment switching.", + "example": "550e8400-e29b-41d4-a716-446655440000" } } }, - "SchedulesTransferOwnershipBody": { + "QueryWaitResponse": { "type": "object", "properties": { - "userId": { - "type": "string", - "format": "uuid", - "description": "The UUID of the user to transfer schedule ownership to. Use the List users endpoint to retrieve user IDs. The new owner must be a member of the same organization, not be the current owner, and have permission to view the dashboard associated with the schedule.", - "example": "987fcdeb-51a2-43d7-9b56-254415f67890" + "results": { + "type": "array", + "items": {}, + "description": "Array of completed query results. Each result contains the query data or an error." } }, "required": [ - "userId" + "results" ] }, - "ScimUsersListResponse": { + "SchedulesListItem": { "type": "object", "properties": { - "Resources": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ScimUserResponse" + "alert": { + "type": "object", + "properties": { + "conditionQueryName": { + "type": [ + "string", + "null" + ], + "description": "Name of the query used for alert condition" + }, + "conditionType": { + "type": "string", + "description": "Type of alert condition: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + } }, - "description": "List of SCIM users" + "required": [ + "conditionQueryName", + "conditionType" + ], + "description": "Alert configuration (only present for alert-type schedules)" }, - "itemsPerPage": { - "type": "number", - "description": "Items per page" + "content": { + "type": "string", + "description": "Content type: dashboard or tile", + "example": "dashboard" }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" + "dashboardName": { + "type": "string", + "description": "Name of the dashboard", + "example": "Weekly Sales Report" }, - "startIndex": { - "type": "number", - "description": "Start index (1-based)" + "destinationType": { + "type": "string", + "description": "Delivery destination type: email, slack, webhook, sftp, s3, google_sheets", + "example": "email" }, - "totalResults": { - "type": "number", - "description": "Total number of results" - } - }, - "required": [ - "Resources", - "itemsPerPage", - "schemas", - "startIndex", - "totalResults" - ] - }, - "ScimUserResponse": { - "type": "object", - "properties": { - "active": { - "type": "boolean", - "description": "Whether the user is active" + "disabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the schedule was paused (null if active)" }, - "displayName": { + "format": { "type": "string", - "description": "Display name" + "description": "Output format: pdf, png, csv, xlsx, json, link_only", + "example": "pdf" }, "id": { "type": "string", "format": "uuid", - "description": "SCIM user ID" - }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" + "description": "Unique identifier for the schedule" }, - "userName": { + "identifier": { "type": "string", - "format": "email", - "description": "Username (email)" - } - }, - "required": [ - "active", - "displayName", - "id", - "schemas", - "userName" - ] - }, - "ScimUserCreateRequest": { - "type": "object", - "properties": { - "displayName": { + "description": "Dashboard identifier", + "example": "12db1a0a" + }, + "lastCompletedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp of last completed delivery" + }, + "lastStatus": { + "type": [ + "string", + "null" + ], + "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" + }, + "name": { "type": "string", - "description": "Display name of the user", - "example": "John Doe" + "description": "Name of the schedule", + "example": "Weekly Sales Report" }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Omni user attributes" + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the schedule owner" }, - "userName": { + "ownerName": { "type": "string", - "format": "email", - "description": "Email address (username) of the user", - "example": "user@example.com" - } - }, - "required": [ - "displayName", - "userName" - ] - }, - "ScimUserPutRequest": { - "type": "object", - "properties": { - "active": { - "type": "boolean", - "default": true, - "description": "Whether the user is active" + "description": "Display name of the schedule owner", + "example": "John Doe" }, - "displayName": { + "recipientCount": { + "type": "number", + "description": "Number of recipients (-1 for non-email destinations)", + "example": 5 + }, + "schedule": { "type": "string", - "description": "Display name of the user" + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" }, - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Enterprise SCIM user attributes" + "slackRecipientType": { + "type": [ + "string", + "null" + ], + "description": "Slack recipient type: Channel or Users (null for non-Slack)" }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - }, - "description": "Omni user attributes" + "systemDisabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when system disabled the schedule (null if not system-disabled)" }, - "userName": { + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + }, + "timezone": { "type": "string", - "format": "email", - "description": "Email address (username) of the user", - "example": "user@example.com" + "description": "IANA timezone for the schedule", + "example": "America/New_York" } }, "required": [ - "userName" + "content", + "dashboardName", + "destinationType", + "disabledAt", + "format", + "id", + "identifier", + "lastCompletedAt", + "lastStatus", + "name", + "ownerId", + "ownerName", + "recipientCount", + "schedule", + "slackRecipientType", + "systemDisabledAt", + "systemDisabledReason", + "timezone" ] }, - "ScimUserPatchRequest": { + "SchedulesGetResponse": { "type": "object", "properties": { - "Operations": { + "conditionQueryMapKey": { + "type": [ + "string", + "null" + ], + "description": "Query key used for alert condition (null for standard schedules)" + }, + "conditionType": { + "type": [ + "string", + "null" + ], + "description": "Alert condition type: RESULTS_CHANGED, RESULTS_PRESENT, RESULTS_MISSING" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "Creation timestamp" + }, + "destinations": { "type": "array", "items": { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace", - "add", - "Add", - "Remove", - "remove" - ] - }, - "path": { - "type": "string" - }, - "value": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": { - "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - } - }, - "urn:omni:params:1.0:UserAttribute": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "type": "string" - } - }, - { - "type": "array", - "items": { - "type": "number" - } - }, - { - "type": "null" - }, - { - "type": "boolean" - }, - { - "type": "object", - "properties": {} - } - ] - } - }, - "active": { - "type": "boolean" - }, - "displayName": { - "type": "string" - }, - "userName": { - "type": "string", - "format": "email" - } - } - } - ] - } - }, - "required": [ - "op", - "value" - ] - }, - "minItems": 1, - "description": "List of patch operations to apply" - }, - "schemas": { - "type": "array", - "items": { - "type": "string", - "enum": [ - "urn:ietf:params:scim:api:messages:2.0:PatchOp" - ] - }, - "description": "SCIM schema URIs" - } - }, - "required": [ - "Operations", - "schemas" - ] - }, - "ScimGroupsListResponse": { - "type": "object", - "properties": { - "Resources": { - "type": "array", - "items": { - "$ref": "#/components/schemas/ScimGroupResponse" + "$ref": "#/components/schemas/SchedulesGetDestination" }, - "description": "List of SCIM groups" + "description": "Delivery destination configurations" }, - "itemsPerPage": { - "type": "number", - "description": "Items per page" + "disabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the schedule was paused (null if active)" }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" + "entityId": { + "type": "string", + "description": "ID of the associated dashboard" }, - "startIndex": { - "type": "number", - "description": "Start index (1-based)" + "fanOut": { + "type": "boolean", + "description": "Whether personalized fan-out delivery is enabled", + "example": false }, - "totalResults": { - "type": "number", - "description": "Total number of results" - } - }, - "required": [ - "Resources", - "itemsPerPage", - "schemas", - "startIndex", - "totalResults" - ] - }, - "ScimGroupResponse": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "Group display name" + "filterConfig": { + "description": "The effective dashboard filter configuration that the schedule will run with: the dashboard's current default filters merged under the schedule's persisted overrides, with any keys no longer present on the dashboard dropped. This matches what is shown when the schedule is opened in the Edit Delivery panel, and may differ from the schedule's persisted filter configuration." }, "id": { "type": "string", - "description": "SCIM group ID (miniUuid)" + "format": "uuid", + "description": "Schedule UUID", + "example": "123e4567-e89b-12d3-a456-426614174000" }, - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Member display name" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "Member user ID" - } - }, - "required": [ - "display", - "value" - ] - }, - "description": "Group members" + "killJobsOnFailure": { + "type": "boolean", + "description": "Whether to stop the job if any queries fail", + "example": false }, - "schemas": { - "type": "array", - "items": { - "type": "string" - }, - "description": "SCIM schema URIs" - } - }, - "required": [ - "displayName", - "id", - "schemas" - ] - }, - "ScimGroupsCreateBody": { - "type": "object", - "properties": { - "displayName": { + "metadata": { + "description": "Schedule metadata including format options and delivery settings" + }, + "name": { "type": "string", - "description": "Display name of the group", - "example": "Engineering Team" + "description": "Schedule name", + "example": "Weekly Sales Report" }, - "members": { - "type": "array", - "items": { - "type": "object", - "properties": { - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] + "organizationId": { + "type": "string", + "format": "uuid", + "description": "Organization UUID" + }, + "owner": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Schedule owner name" + } }, - "default": [], - "description": "List of group members" + "required": [ + "name" + ] + }, + "ownerId": { + "type": "string", + "format": "uuid", + "description": "User ID of the schedule owner" + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (minute hour day-of-month month day-of-week year)", + "example": "0 9 ? * MON *" + }, + "systemDisabledAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp when the system disabled the schedule" + }, + "systemDisabledReason": { + "type": [ + "string", + "null" + ], + "description": "Reason for system disabling: missingQuery, noAccess, orphanedFilterConfigKeys" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for the schedule", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" } }, "required": [ - "displayName" + "conditionQueryMapKey", + "conditionType", + "createdAt", + "destinations", + "disabledAt", + "entityId", + "fanOut", + "id", + "killJobsOnFailure", + "name", + "organizationId", + "owner", + "ownerId", + "schedule", + "systemDisabledAt", + "systemDisabledReason", + "timezone", + "updatedAt" ] }, - "ScimGroupsReplaceBody": { + "SchedulesGetDestination": { "type": "object", "properties": { - "displayName": { + "format": { "type": "string", - "description": "Display name of the group", - "example": "Engineering Team" + "description": "Output format: pdf, png, csv, xlsx, json, link_only", + "example": "pdf" }, - "members": { + "id": { + "type": "string", + "format": "uuid", + "description": "Destination UUID" + }, + "lastCompletedAt": { + "type": [ + "string", + "null" + ], + "format": "date-time", + "description": "Timestamp of last completed delivery" + }, + "lastStatus": { + "type": [ + "string", + "null" + ], + "description": "Status of last delivery: COMPLETE, ERROR, ERROR_DELIVERED, KILLED, CONDITION_UNMET" + }, + "metadata": { + "description": "Destination-specific configuration (type, recipients, credentials, etc.)" + }, + "recipients": { "type": "array", "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" + "$ref": "#/components/schemas/SchedulesGetRecipient" + }, + "description": "Individual email recipients" + }, + "userGroupRecipients": { + "type": "array", + "items": {}, + "description": "User group recipients" + } + }, + "required": [ + "format", + "id", + "lastCompletedAt", + "lastStatus", + "recipients", + "userGroupRecipients" + ] + }, + "SchedulesGetRecipient": { + "type": "object", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Recipient ID" + }, + "membership": { + "type": "object", + "properties": { + "user": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Recipient email" + }, + "name": { + "type": [ + "string", + "null" + ], + "description": "Recipient name" + } }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "display", - "value" - ] + "required": [ + "email", + "name" + ] + } }, - "description": "List of group members" + "required": [ + "user" + ] + }, + "membershipId": { + "type": "string", + "format": "uuid", + "description": "Membership ID" } }, "required": [ - "displayName", - "members" + "id", + "membership", + "membershipId" ] }, - "ScimGroupsPatchBody": { + "SchedulesRecipientsGetResponse": { "type": "object", "properties": { - "Operations": { + "recipients": { "type": "array", "items": { - "anyOf": [ - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace" - ], - "description": "Operation type", - "example": "replace" - }, - "value": { - "type": "object", - "properties": { - "displayName": { - "type": "string", - "description": "New display name", - "example": "Engineering Team" - }, - "id": { - "type": "string", - "description": "Group ID" - } - }, - "required": [ - "displayName" - ] - } - }, - "required": [ - "op", - "value" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "remove", - "Remove" - ], - "description": "Operation type", - "example": "remove" - }, - "path": { - "type": "string", - "pattern": "members\\[value eq \"(.{36})\"\\]", - "description": "SCIM path for member to remove", - "example": "members[value eq \"550e8400-e29b-41d4-a716-446655440000\"]" - } - }, - "required": [ - "op", - "path" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "add", - "Add" - ], - "description": "Operation type", - "example": "add" - }, - "path": { - "type": "string", - "enum": [ - "members" - ], - "description": "Path for members", - "example": "members" - }, - "value": { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] - } - } - }, - "required": [ - "op", - "path", - "value" - ] - }, - { - "type": "object", - "properties": { - "op": { - "type": "string", - "enum": [ - "replace", - "Replace" - ], - "description": "Operation type", - "example": "replace" - }, - "path": { - "type": "string", - "enum": [ - "members", - "displayName" - ], - "description": "Path for attribute to replace", - "example": "members" - }, - "value": { - "anyOf": [ - { - "type": "array", - "items": { - "type": "object", - "properties": { - "display": { - "type": "string", - "description": "Display name of the member", - "example": "john.doe@example.com" - }, - "value": { - "type": "string", - "format": "uuid", - "description": "User membership ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - } - }, - "required": [ - "value" - ] - } - }, - { - "type": "string" - } - ] - } - }, - "required": [ - "op", - "path", - "value" - ] - } - ] + "$ref": "#/components/schemas/EmailRecipient" }, - "description": "List of SCIM patch operations" + "description": "List of individual recipients (for email destinations)." }, - "schemas": { + "type": { + "type": "string", + "enum": [ + "email", + "google_sheets", + "s3", + "sftp", + "slack", + "webhook" + ], + "description": "The schedule's destination type.", + "example": "email" + }, + "userGroupRecipients": { "type": "array", "items": { - "type": "string", - "enum": [ - "urn:ietf:params:scim:api:messages:2.0:PatchOp" - ] + "$ref": "#/components/schemas/UserGroupRecipient" }, - "description": "SCIM schema URIs" + "description": "List of user group recipients (for email destinations)." } }, "required": [ - "Operations", - "schemas" + "type" ] }, - "DocumentExportResponse": { + "EmailRecipient": { "type": "object", "properties": { - "dashboard": { - "description": "Dashboard configuration and layout" - }, - "document": { - "type": "object", - "properties": { - "ephemeral": { - "type": "string" - }, - "name": { - "type": "string" - } - }, - "required": [ - "name" - ] - }, - "exportVersion": { - "type": "string" - }, - "fileUploads": { - "type": "object", - "additionalProperties": {} + "email": { + "type": "string", + "format": "email", + "description": "Recipient's email address.", + "example": "user@example.com" }, - "queryModels": { - "type": "object", - "additionalProperties": {} + "id": { + "type": "string", + "description": "Unique identifier for the recipient." }, - "workbookModel": {} + "name": { + "type": "string", + "description": "Recipient's display name.", + "example": "John Doe" + } }, "required": [ - "document", - "exportVersion", - "queryModels" + "email", + "id", + "name" ] }, - "DocumentImportResponse": { + "UserGroupRecipient": { "type": "object", "properties": { - "documentId": { + "id": { "type": "string", - "format": "uuid", - "description": "ID of the imported document" + "description": "User group ID." }, - "identifier": { + "name": { "type": "string", - "description": "Document identifier (miniUuid)" + "description": "User group name.", + "example": "Sales Team" + }, + "recipients": { + "type": "array", + "items": { + "$ref": "#/components/schemas/EmailRecipient" + }, + "description": "List of recipients in the user group." } }, "required": [ - "documentId", - "identifier" + "id", + "name", + "recipients" ] }, - "DocumentImportBody": { + "SchedulesAddRecipientsResponse": { "type": "object", "properties": { - "baseModelId": { - "type": "string", - "format": "uuid", - "description": "Base model ID for the imported document" + "addedGroupRecipientsCount": { + "type": "number", + "description": "Number of user group recipients added.", + "example": 1 }, - "dashboard": { - "description": "Dashboard export data" + "addedRecipientsCount": { + "type": "number", + "description": "Number of individual recipients added.", + "example": 2 }, - "document": { - "type": "object", - "properties": { - "ephemeral": { - "type": "string" - }, - "name": { - "type": "string" - } + "success": { + "type": "boolean", + "description": "Whether the operation was successful.", + "example": true + } + }, + "required": [ + "addedGroupRecipientsCount", + "addedRecipientsCount", + "success" + ] + }, + "SchedulesAddRecipientsBody": { + "type": "object", + "properties": { + "emails": { + "type": "array", + "items": { + "type": "string", + "format": "email" }, - "required": [ - "name" - ] - }, - "exportVersion": { - "type": "string", - "enum": [ - "0.1" + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of email addresses to add as recipients.", + "example": [ + "user@example.com" ] }, - "fileUploads": { - "type": "object", - "additionalProperties": {} - }, - "folderPath": { - "type": "string" + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to add as recipients.", + "example": [ + "123e4567-e89b-12d3-a456-426614174000" + ] }, - "identifier": { - "type": "string" + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user UUIDs to add as recipients. Use the List users and List embed users endpoints to retrieve user IDs.", + "example": [ + "987fcdeb-51a2-43d7-9b56-254415f67890" + ] + } + } + }, + "SchedulesRemoveRecipientsResponse": { + "type": "object", + "properties": { + "removedGroupRecipientsCount": { + "type": "number", + "description": "Number of user group recipients removed.", + "example": 1 }, - "queryModels": { - "type": "object", - "additionalProperties": {} + "removedRecipientsCount": { + "type": "number", + "description": "Number of individual recipients removed.", + "example": 2 }, - "workbookModel": {} + "success": { + "type": "boolean", + "description": "Whether the operation was successful.", + "example": true + } }, "required": [ - "baseModelId", - "document", - "exportVersion", - "queryModels" + "removedGroupRecipientsCount", + "removedRecipientsCount", + "success" ] }, - "UserAttributesListResponse": { + "SchedulesRemoveRecipientsBody": { "type": "object", "properties": { - "records": { + "emails": { "type": "array", "items": { - "type": "object", - "properties": { - "default_value": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "array", - "items": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - } - ] - } - }, - { - "type": "null" - } - ], - "description": "Default value applied when no user-specific value is set. When multiple_values is true, this is an array. Null if no default is configured.", - "example": "us-east" - }, - "description": { - "type": [ - "string", - "null" - ], - "description": "Human-readable description of the attribute and its purpose", - "example": "User region for row-level security filtering" - }, - "id": { - "type": "string", - "description": "Unique identifier for custom attributes. Empty string for system-defined attributes.", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "label": { - "type": "string", - "description": "Display name shown in the Omni UI", - "example": "Region" - }, - "multiple_values": { - "type": "boolean", - "description": "Whether the attribute accepts an array of values. When true, default_value and user-specific values are arrays.", - "example": false - }, - "name": { - "type": "string", - "description": "Reference name used in model SQL and in embed SSO URL parameters", - "example": "region" - }, - "system": { - "type": "boolean", - "description": "System-defined attributes (e.g. omni_user_id, omni_user_email) are built-in and read-only. Custom attributes have system=false.", - "example": false - }, - "type": { - "type": "string", - "enum": [ - "String", - "Number" - ], - "description": "Data type that determines valid values. String attributes accept text, Number attributes accept numeric values stored as strings for precision.", - "example": "String" - } - }, - "required": [ - "default_value", - "description", - "id", - "label", - "multiple_values", - "name", - "system", - "type" - ] + "type": "string", + "format": "email" }, - "description": "All user attribute definitions in the organization, including both system-defined and custom attributes" + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of recipient email addresses to remove from the scheduled task.", + "example": [ + "user@example.com" + ] + }, + "userGroupIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of user group UUIDs to remove as recipients.", + "example": [ + "123e4567-e89b-12d3-a456-426614174000" + ] + }, + "userIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "default": [], + "description": "At least one email, userId, or userGroupId must be provided. Array of recipient user UUIDs to remove from the scheduled task. Use the List users and List embed users endpoints to retrieve user IDs.", + "example": [ + "987fcdeb-51a2-43d7-9b56-254415f67890" + ] + } + } + }, + "SchedulesTransferOwnershipBody": { + "type": "object", + "properties": { + "userId": { + "type": "string", + "format": "uuid", + "description": "The UUID of the user to transfer schedule ownership to. Use the List users endpoint to retrieve user IDs. The new owner must be a member of the same organization, not be the current owner, and have permission to view the dashboard associated with the schedule.", + "example": "987fcdeb-51a2-43d7-9b56-254415f67890" } }, "required": [ - "records" + "userId" ] }, - "UploadsListResponse": { + "ScimUsersListResponse": { "type": "object", "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + "Resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScimUserResponse" + }, + "description": "List of SCIM users" }, - "records": { + "itemsPerPage": { + "type": "number", + "description": "Items per page" + }, + "schemas": { "type": "array", "items": { - "$ref": "#/components/schemas/Upload" - } + "type": "string" + }, + "description": "SCIM schema URIs" + }, + "startIndex": { + "type": "number", + "description": "Start index (1-based)" + }, + "totalResults": { + "type": "number", + "description": "Total number of results" } }, "required": [ - "pageInfo", - "records" + "Resources", + "itemsPerPage", + "schemas", + "startIndex", + "totalResults" ] }, - "Upload": { + "ScimUserResponse": { "type": "object", "properties": { - "connection_id": { - "type": "string", - "format": "uuid", - "description": "Connection ID the upload is associated with" - }, - "created_at": { - "type": "string", - "format": "date-time", - "description": "When the file was uploaded" + "active": { + "type": "boolean", + "description": "Whether the user is active" }, - "file_name": { + "displayName": { "type": "string", - "description": "Original file name", - "example": "users.csv" + "description": "Display name" }, "id": { "type": "string", "format": "uuid", - "description": "Unique identifier for the upload" - }, - "in_db_as_table_name": { - "type": [ - "string", - "null" - ], - "description": "Database table name if uploaded to database scratch schema" - }, - "model_id": { - "type": [ - "string", - "null" - ], - "format": "uuid", - "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" - }, - "size_bytes": { - "type": [ - "number", - "null" - ], - "description": "File size in bytes" - }, - "updated_at": { - "type": "string", - "format": "date-time", - "description": "Last update timestamp" + "description": "SCIM user ID" }, - "uploaded_by_user": { - "type": [ - "object", - "null" - ], - "properties": { - "id": { - "type": "string", - "format": "uuid", - "description": "User ID of the uploader" - }, - "name": { - "type": "string", - "description": "Name of the user who uploaded the file" - } + "schemas": { + "type": "array", + "items": { + "type": "string" }, - "required": [ - "id", - "name" - ], - "description": "User who uploaded the file" + "description": "SCIM schema URIs" }, - "view_name": { + "userName": { "type": "string", - "description": "View name associated with the upload" + "format": "email", + "description": "Username (email)" } }, "required": [ - "connection_id", - "created_at", - "file_name", + "active", + "displayName", "id", - "in_db_as_table_name", - "model_id", - "size_bytes", - "updated_at", - "uploaded_by_user", - "view_name" + "schemas", + "userName" ] }, - "UploadCreateResponse": { + "ScimUserCreateRequest": { "type": "object", "properties": { - "fileName": { - "type": "string", - "description": "Original file name", - "example": "users.csv" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique identifier for the upload" - }, - "inDbAsTableName": { - "type": "string", - "description": "Database table name in the scratch schema" - }, - "modelId": { + "displayName": { "type": "string", - "format": "uuid", - "description": "Model ID the view was created in" - }, - "rowCount": { - "type": "integer", - "description": "Number of rows in the uploaded file" - }, - "truncated": { - "type": "boolean", - "description": "Whether the file was truncated due to row limit" + "description": "Display name of the user", + "example": "John Doe" }, - "viewCreated": { - "type": "boolean", - "description": "Whether a view was created in the model" + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Omni user attributes" }, - "viewName": { + "userName": { "type": "string", - "description": "Name of the view created" + "format": "email", + "description": "Email address (username) of the user", + "example": "user@example.com" } }, "required": [ - "fileName", - "id", - "inDbAsTableName", - "modelId", - "rowCount", - "truncated", - "viewCreated", - "viewName" + "displayName", + "userName" ] }, - "UploadCreateBody": { + "ScimUserPutRequest": { "type": "object", "properties": { - "branchId": { - "type": "string", - "format": "uuid", - "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" + "active": { + "type": "boolean", + "default": true, + "description": "Whether the user is active" }, - "branchName": { + "displayName": { "type": "string", - "description": "Name of the branch to create the view in (mutually exclusive with branchId)" + "description": "Display name of the user" }, - "file": { - "type": "string", - "description": "The CSV file to upload", - "format": "binary" + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Enterprise SCIM user attributes" }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "UUID of the model to create the view in" + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + }, + "description": "Omni user attributes" }, - "viewName": { + "userName": { "type": "string", - "description": "Override the view name (defaults to sanitized file name)" + "format": "email", + "description": "Email address (username) of the user", + "example": "user@example.com" } }, "required": [ - "file", - "modelId" + "userName" ] }, - "UploadDeleteResponse": { + "ScimUserPatchRequest": { "type": "object", "properties": { - "success": { - "type": "boolean", - "description": "Whether the deletion was successful" + "Operations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace", + "add", + "Add", + "Remove", + "remove" + ] + }, + "path": { + "type": "string" + }, + "value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": { + "urn:ietf:params:scim:schemas:extension:enterprise:2.0:User": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "urn:omni:params:1.0:UserAttribute": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "array", + "items": { + "type": "number" + } + }, + { + "type": "null" + }, + { + "type": "boolean" + }, + { + "type": "object", + "properties": {} + } + ] + } + }, + "active": { + "type": "boolean" + }, + "displayName": { + "type": "string" + }, + "userName": { + "type": "string", + "format": "email" + } + } + } + ] + } + }, + "required": [ + "op", + "value" + ] + }, + "minItems": 1, + "description": "List of patch operations to apply" + }, + "schemas": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "urn:ietf:params:scim:api:messages:2.0:PatchOp" + ] + }, + "description": "SCIM schema URIs" } }, "required": [ - "success" + "Operations", + "schemas" ] }, - "UsersGetModelRolesResponse": { + "ScimGroupsListResponse": { "type": "object", "properties": { - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" + "Resources": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ScimGroupResponse" + }, + "description": "List of SCIM groups" }, - "results": { + "itemsPerPage": { + "type": "number", + "description": "Items per page" + }, + "schemas": { "type": "array", "items": { - "$ref": "#/components/schemas/RoleAssignmentResult" + "type": "string" }, - "description": "List of role assignments" + "description": "SCIM schema URIs" + }, + "startIndex": { + "type": "number", + "description": "Start index (1-based)" + }, + "totalResults": { + "type": "number", + "description": "Total number of results" } }, "required": [ - "membershipId", - "results" + "Resources", + "itemsPerPage", + "schemas", + "startIndex", + "totalResults" ] }, - "RoleAssignmentResult": { + "ScimGroupResponse": { "type": "object", "properties": { - "baseRole": { - "type": "string", - "description": "The base role definition name", - "example": "VIEWER" - }, - "connectionId": { + "displayName": { "type": "string", - "format": "uuid", - "description": "Connection this role applies to" - }, - "from": { - "$ref": "#/components/schemas/RoleOrigin" + "description": "Group display name" }, - "modelId": { + "id": { "type": "string", - "format": "uuid", - "description": "Model this role applies to" - }, - "priority": { - "type": "number", - "description": "Priority for role resolution (higher = more permissive)" + "description": "SCIM group ID (miniUuid)" }, - "resolved": { - "type": "boolean", - "description": "Whether this is the resolved (effective) role" + "members": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Member display name" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "Member user ID" + } + }, + "required": [ + "display", + "value" + ] + }, + "description": "Group members" }, - "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" + "schemas": { + "type": "array", + "items": { + "type": "string" + }, + "description": "SCIM schema URIs" } }, "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "resolved", - "roleName" - ] - }, - "RoleOrigin": { - "oneOf": [ - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "USER" - ], - "description": "Role assigned directly to user" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "ORG" - ], - "description": "Role inherited from organization" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "type": { - "type": "string", - "enum": [ - "BASE" - ], - "description": "Connection base role" - } - }, - "required": [ - "type" - ] - }, - { - "type": "object", - "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { - "type": "string", - "description": "Name of the group", - "example": "Engineering Team" - }, - "type": { - "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role inherited from group membership" - } - }, - "required": [ - "depth", - "miniUuid", - "name", - "type" - ] - } - ], - "description": "Origin of this role assignment" - }, - "UsersAssignModelRoleResponse": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "The connection ID for this role assignment" - }, - "membershipId": { - "type": "string", - "format": "uuid", - "description": "The user membership ID" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The model ID for this role assignment" - }, - "roleName": { - "type": "string", - "description": "The assigned role name", - "example": "VIEWER" - } - }, - "required": [ - "connectionId", - "membershipId", - "modelId", - "roleName" + "displayName", + "id", + "schemas" ] }, - "UsersAssignModelRoleBody": { + "ScimGroupsCreateBody": { "type": "object", "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model ID for model-level role assignment. Required if connectionId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "roleName": { + "displayName": { "type": "string", - "minLength": 1, - "description": "Name of the role to assign (base or custom role)", - "example": "VIEWER" - } - }, - "required": [ - "roleName" - ] - }, - "UsersListEmailOnlyResponse": { - "type": "object", - "properties": { - "pageInfo": { - "$ref": "#/components/schemas/PageInfo" + "description": "Display name of the group", + "example": "Engineering Team" }, - "records": { + "members": { "type": "array", "items": { "type": "object", "properties": { - "email": { - "type": "string", - "description": "User email address", - "example": "user@example.com" - }, - "user_attributes": { - "type": "object", - "additionalProperties": {}, - "description": "User attributes as key-value pairs" - }, - "user_id": { + "value": { "type": "string", "format": "uuid", - "description": "User ID" + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" } }, "required": [ - "email", - "user_attributes", - "user_id" + "value" ] - } - } - }, - "required": [ - "pageInfo", - "records" - ] - }, - "UsersCreateEmailOnlyResponse": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" - }, - "userId": { - "type": "string", - "format": "uuid", - "description": "ID of the created user" + }, + "default": [], + "description": "List of group members" } }, "required": [ - "email", - "userId" + "displayName" ] }, - "UsersCreateEmailOnlyBody": { + "ScimGroupsReplaceBody": { "type": "object", "properties": { - "email": { + "displayName": { "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" + "description": "Display name of the group", + "example": "Engineering Team" }, - "userAttributes": { - "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" - }, - { - "type": "null" - } - ] - }, - "description": "Optional user attributes as key-value pairs" - } - }, - "required": [ - "email" - ] - }, - "UsersCreateEmailOnlyBulkResponse": { - "type": "object", - "properties": { - "results": { + "members": { "type": "array", "items": { "type": "object", "properties": { - "email": { + "display": { "type": "string", - "format": "email", - "description": "Email address of the created user", - "example": "user@example.com" + "description": "Display name of the member", + "example": "john.doe@example.com" }, - "userId": { + "value": { "type": "string", "format": "uuid", - "description": "ID of the created user" + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" } }, "required": [ - "email", - "userId" + "display", + "value" ] }, - "description": "Results for each created user" + "description": "List of group members" } }, "required": [ - "results" + "displayName", + "members" ] }, - "UsersCreateEmailOnlyBulkBody": { + "ScimGroupsPatchBody": { "type": "object", "properties": { - "users": { + "Operations": { "type": "array", "items": { - "type": "object", - "properties": { - "email": { - "type": "string", - "format": "email", - "description": "Email address for the user", - "example": "user@example.com" - }, - "userAttributes": { + "anyOf": [ + { "type": "object", - "additionalProperties": { - "anyOf": [ - { - "type": "string" - }, - { - "type": "number" - }, - { - "type": "boolean" + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace" + ], + "description": "Operation type", + "example": "replace" + }, + "value": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "New display name", + "example": "Engineering Team" + }, + "id": { + "type": "string", + "description": "Group ID" + } }, - { - "type": "null" + "required": [ + "displayName" + ] + } + }, + "required": [ + "op", + "value" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "remove", + "Remove" + ], + "description": "Operation type", + "example": "remove" + }, + "path": { + "type": "string", + "pattern": "members\\[value eq \"(.{36})\"\\]", + "description": "SCIM path for member to remove", + "example": "members[value eq \"550e8400-e29b-41d4-a716-446655440000\"]" + } + }, + "required": [ + "op", + "path" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "add", + "Add" + ], + "description": "Operation type", + "example": "add" + }, + "path": { + "type": "string", + "enum": [ + "members" + ], + "description": "Path for members", + "example": "members" + }, + "value": { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] } - ] + } }, - "description": "Optional user attributes as key-value pairs" + "required": [ + "op", + "path", + "value" + ] + }, + { + "type": "object", + "properties": { + "op": { + "type": "string", + "enum": [ + "replace", + "Replace" + ], + "description": "Operation type", + "example": "replace" + }, + "path": { + "type": "string", + "enum": [ + "members", + "displayName" + ], + "description": "Path for attribute to replace", + "example": "members" + }, + "value": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "object", + "properties": { + "display": { + "type": "string", + "description": "Display name of the member", + "example": "john.doe@example.com" + }, + "value": { + "type": "string", + "format": "uuid", + "description": "User membership ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + } + }, + "required": [ + "value" + ] + } + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "op", + "path", + "value" + ] } - }, - "required": [ - "email" ] }, - "minItems": 1, - "maxItems": 20, - "description": "Array of users to create (1-20 users)" - } - }, - "required": [ - "users" - ] - }, - "UserGroupsGetModelRolesResponse": { - "type": "object", - "properties": { - "results": { + "description": "List of SCIM patch operations" + }, + "schemas": { "type": "array", "items": { - "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" + "type": "string", + "enum": [ + "urn:ietf:params:scim:api:messages:2.0:PatchOp" + ] }, - "description": "List of role assignments" - }, - "userGroupId": { - "type": "string", - "description": "The user group short identifier", - "example": "abc123" + "description": "SCIM schema URIs" } }, "required": [ - "results", - "userGroupId" + "Operations", + "schemas" ] }, - "UserGroupRoleAssignmentResult": { + "DocumentExportResponse": { "type": "object", "properties": { - "baseRole": { - "type": "string", - "description": "The base role definition name", - "example": "VIEWER" + "dashboard": { + "description": "Dashboard configuration and layout" }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection this role applies to" + "document": { + "type": "object", + "properties": { + "ephemeral": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] }, - "from": { - "$ref": "#/components/schemas/UserGroupRoleOrigin" + "exportVersion": { + "type": "string" }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "Model this role applies to" + "fileUploads": { + "type": "object", + "additionalProperties": {} }, - "priority": { - "type": "number", - "description": "Priority for role resolution (higher = more permissive)" + "queryModels": { + "type": "object", + "additionalProperties": {} }, - "roleName": { - "type": "string", - "description": "The role name (base or custom)", - "example": "VIEWER" - } + "workbookModel": {} }, "required": [ - "baseRole", - "connectionId", - "from", - "modelId", - "priority", - "roleName" + "document", + "exportVersion", + "queryModels" ] }, - "UserGroupRoleOrigin": { + "DocumentImportResponse": { "type": "object", "properties": { - "depth": { - "type": "number", - "description": "Nesting depth of the group (0 for direct assignment)" - }, - "miniUuid": { - "type": "string", - "description": "Short identifier of the group", - "example": "abc123" - }, - "name": { + "documentId": { "type": "string", - "description": "Name of the group", - "example": "Engineering Team" + "format": "uuid", + "description": "ID of the imported document" }, - "type": { + "identifier": { "type": "string", - "enum": [ - "GROUP" - ], - "description": "Role assigned to group" + "description": "Document identifier (miniUuid)" } }, "required": [ - "depth", - "miniUuid", - "name", - "type" - ], - "description": "Origin of this role assignment" + "documentId", + "identifier" + ] }, - "UserGroupsAssignModelRoleResponse": { + "DocumentImportBody": { "type": "object", "properties": { - "connectionId": { + "baseModelId": { "type": "string", "format": "uuid", - "description": "The connection ID for this role assignment" + "description": "Base model ID for the imported document" }, - "modelId": { - "type": "string", - "format": "uuid", - "description": "The model ID for this role assignment" + "dashboard": { + "description": "Dashboard export data" }, - "roleName": { - "type": "string", - "description": "The assigned role name", - "example": "VIEWER" + "document": { + "type": "object", + "properties": { + "ephemeral": { + "type": "string" + }, + "name": { + "type": "string" + } + }, + "required": [ + "name" + ] }, - "userGroupId": { + "exportVersion": { "type": "string", - "description": "The user group short identifier", - "example": "abc123" + "enum": [ + "0.1" + ] + }, + "fileUploads": { + "type": "object", + "additionalProperties": {} + }, + "folderPath": { + "type": "string" + }, + "identifier": { + "type": "string" + }, + "queryModels": { + "type": "object", + "additionalProperties": {} + }, + "workbookModel": {} + }, + "required": [ + "baseModelId", + "document", + "exportVersion", + "queryModels" + ] + }, + "UserAttributesListResponse": { + "type": "object", + "properties": { + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "default_value": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "array", + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ] + } + }, + { + "type": "null" + } + ], + "description": "Default value applied when no user-specific value is set. When multiple_values is true, this is an array. Null if no default is configured.", + "example": "us-east" + }, + "description": { + "type": [ + "string", + "null" + ], + "description": "Human-readable description of the attribute and its purpose", + "example": "User region for row-level security filtering" + }, + "id": { + "type": "string", + "description": "Unique identifier for custom attributes. Empty string for system-defined attributes.", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "label": { + "type": "string", + "description": "Display name shown in the Omni UI", + "example": "Region" + }, + "multiple_values": { + "type": "boolean", + "description": "Whether the attribute accepts an array of values. When true, default_value and user-specific values are arrays.", + "example": false + }, + "name": { + "type": "string", + "description": "Reference name used in model SQL and in embed SSO URL parameters", + "example": "region" + }, + "system": { + "type": "boolean", + "description": "System-defined attributes (e.g. omni_user_id, omni_user_email) are built-in and read-only. Custom attributes have system=false.", + "example": false + }, + "type": { + "type": "string", + "enum": [ + "String", + "Number" + ], + "description": "Data type that determines valid values. String attributes accept text, Number attributes accept numeric values stored as strings for precision.", + "example": "String" + } + }, + "required": [ + "default_value", + "description", + "id", + "label", + "multiple_values", + "name", + "system", + "type" + ] + }, + "description": "All user attribute definitions in the organization, including both system-defined and custom attributes" } }, "required": [ - "connectionId", - "modelId", - "roleName", - "userGroupId" + "records" ] }, - "UserGroupsAssignModelRoleBody": { + "UploadsListResponse": { "type": "object", "properties": { - "connectionId": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Upload" + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "Upload": { + "type": "object", + "properties": { + "connection_id": { "type": "string", "format": "uuid", - "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection ID the upload is associated with" }, - "modelId": { + "created_at": { "type": "string", - "format": "uuid", - "description": "Model ID for model-level role assignment. Required if connectionId not provided.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "format": "date-time", + "description": "When the file was uploaded" }, - "roleName": { + "file_name": { "type": "string", - "minLength": 1, - "description": "Name of the role to assign (base or custom role)", - "example": "VIEWER" - } - }, - "required": [ - "roleName" - ] - } - }, - "parameters": {} - }, - "paths": { - "/api/v1/ai/generate-query": { - "post": { - "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", - "operationId": "aiGenerateQuery", - "summary": "Generate query from natural language", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiGenerateQueryBody" - } - } - } - }, - "responses": { - "200": { - "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiGenerateQueryResponse" - } - } - } + "description": "Original file name", + "example": "users.csv" }, - "400": { - "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "in_db_as_table_name": { + "type": [ + "string", + "null" + ], + "description": "Database table name if uploaded to database scratch schema" }, - "402": { - "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiCreditShutoffError" - } - } - } + "model_id": { + "type": [ + "string", + "null" + ], + "format": "uuid", + "description": "Model ID the upload is associated with (inferred from connection's shared model if not explicitly set)" }, - "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "size_bytes": { + "type": [ + "number", + "null" + ], + "description": "File size in bytes" }, - "404": { - "description": "The specified model or topic was not found in the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "updated_at": { + "type": "string", + "format": "date-time", + "description": "Last update timestamp" }, - "500": { - "description": "AI service error." - } - } - } - }, - "/api/v1/ai/pick-topic": { - "post": { - "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", - "operationId": "aiPickTopic", - "summary": "Pick the best topic for a prompt", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiPickTopicBody" + "uploaded_by_user": { + "type": [ + "object", + "null" + ], + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "User ID of the uploader" + }, + "name": { + "type": "string", + "description": "Name of the user who uploaded the file" } - } + }, + "required": [ + "id", + "name" + ], + "description": "User who uploaded the file" + }, + "view_name": { + "type": "string", + "description": "View name associated with the upload" } }, - "responses": { - "200": { - "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiPickTopicResponse" - } - } - } + "required": [ + "connection_id", + "created_at", + "file_name", + "id", + "in_db_as_table_name", + "model_id", + "size_bytes", + "updated_at", + "uploaded_by_user", + "view_name" + ] + }, + "UploadCreateResponse": { + "type": "object", + "properties": { + "fileName": { + "type": "string", + "description": "Original file name", + "example": "users.csv" }, - "400": { - "description": "Invalid request body. The prompt or modelId may be missing or malformed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the upload" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "inDbAsTableName": { + "type": "string", + "description": "Database table name in the scratch schema" }, - "403": { - "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID the view was created in" }, - "404": { - "description": "The specified model was not found, or no accessible topics exist in the model.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "rowCount": { + "type": "integer", + "description": "Number of rows in the uploaded file" }, - "500": { - "description": "AI service error." - } - } - } - }, - "/api/v1/ai/search-omni-docs": { - "post": { - "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", - "operationId": "aiSearchOmniDocs", - "summary": "Search Omni documentation", - "tags": [ - "AI" - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsBody" - } - } + "truncated": { + "type": "boolean", + "description": "Whether the file was truncated due to row limit" + }, + "viewCreated": { + "type": "boolean", + "description": "Whether a view was created in the model" + }, + "viewName": { + "type": "string", + "description": "Name of the view created" } }, - "responses": { - "200": { - "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiSearchOmniDocsResponse" - } - } - } + "required": [ + "fileName", + "id", + "inDbAsTableName", + "modelId", + "rowCount", + "truncated", + "viewCreated", + "viewName" + ] + }, + "UploadCreateBody": { + "type": "object", + "properties": { + "branchId": { + "type": "string", + "format": "uuid", + "description": "UUID of the branch to create the view in (mutually exclusive with branchName)" }, - "400": { - "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "branchName": { + "type": "string", + "description": "Name of the branch to create the view in (mutually exclusive with branchId)" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "file": { + "type": "string", + "description": "The CSV file to upload", + "format": "binary" }, - "403": { - "description": "Omni Agent is not enabled for this organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "UUID of the model to create the view in" }, - "500": { - "description": "AI service error." + "viewName": { + "type": "string", + "description": "Override the view name (defaults to sanitized file name)" } - } - } - }, - "/api/v1/ai/jobs": { - "post": { - "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", - "operationId": "aiJobSubmit", - "summary": "Submit an AI job", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + }, + "required": [ + "file", + "modelId" + ] + }, + "UploadDeleteResponse": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the deletion was successful" } - ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitBody" - } - } + }, + "required": [ + "success" + ] + }, + "UsersGetModelRolesResponse": { + "type": "object", + "properties": { + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" + }, + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RoleAssignmentResult" + }, + "description": "List of role assignments" } }, - "responses": { - "201": { - "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobSubmitResponse" - } - } - } + "required": [ + "membershipId", + "results" + ] + }, + "RoleAssignmentResult": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The base role definition name", + "example": "VIEWER" }, - "400": { - "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection this role applies to" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "from": { + "$ref": "#/components/schemas/RoleOrigin" }, - "403": { - "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model this role applies to" }, - "404": { - "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" }, - "409": { - "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } + "resolved": { + "type": "boolean", + "description": "Whether this is the resolved (effective) role" + }, + "roleName": { + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" } - } - } - }, - "/api/v1/ai/jobs/{jobId}": { - "get": { - "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", - "operationId": "aiJobStatus", - "summary": "Get AI job status", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobStatusResponse" - } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "resolved", + "roleName" + ] + }, + "RoleOrigin": { + "oneOf": [ + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "USER" + ], + "description": "Role assigned directly to user" } - } + }, + "required": [ + "type" + ] }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "ORG" + ], + "description": "Role inherited from organization" } - } + }, + "required": [ + "type" + ] }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } + { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "BASE" + ], + "description": "Connection base role" } - } + }, + "required": [ + "type" + ] }, - "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } - } - } - } - }, - "/api/v1/ai/jobs/{jobId}/cancel": { - "post": { - "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", - "operationId": "aiJobCancel", - "summary": "Cancel an AI job", - "tags": [ - "AI" - ], - "parameters": [ { - "schema": { - "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role inherited from group membership" + } }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" + "required": [ + "depth", + "miniUuid", + "name", + "type" + ] } ], - "responses": { - "200": { - "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiJobCancelResponse" - } - } - } + "description": "Origin of this role assignment" + }, + "UsersAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "membershipId": { + "type": "string", + "format": "uuid", + "description": "The user membership ID" }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" }, - "403": { - "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + } + }, + "required": [ + "connectionId", + "membershipId", + "modelId", + "roleName" + ] + }, + "UsersAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "404": { - "description": "Job not found. The job may not exist or may belong to a different organization.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } - } - } + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "409": { - "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError409" - } - } - } + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" } - } - } - }, - "/api/v1/ai/jobs/{jobId}/result": { - "get": { - "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", - "operationId": "aiJobResult", - "summary": "Get AI job result", - "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { + }, + "required": [ + "roleName" + ] + }, + "UsersListEmailOnlyResponse": { + "type": "object", + "properties": { + "pageInfo": { + "$ref": "#/components/schemas/PageInfo" + }, + "records": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "description": "User email address", + "example": "user@example.com" + }, + "user_attributes": { + "type": "object", + "additionalProperties": {}, + "description": "User attributes as key-value pairs" + }, + "user_id": { + "type": "string", + "format": "uuid", + "description": "User ID" + } + }, + "required": [ + "email", + "user_attributes", + "user_id" + ] + } + } + }, + "required": [ + "pageInfo", + "records" + ] + }, + "UsersCreateEmailOnlyResponse": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "UsersCreateEmailOnlyBody": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "UsersCreateEmailOnlyBulkResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address of the created user", + "example": "user@example.com" + }, + "userId": { + "type": "string", + "format": "uuid", + "description": "ID of the created user" + } + }, + "required": [ + "email", + "userId" + ] + }, + "description": "Results for each created user" + } + }, + "required": [ + "results" + ] + }, + "UsersCreateEmailOnlyBulkBody": { + "type": "object", + "properties": { + "users": { + "type": "array", + "items": { + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "description": "Email address for the user", + "example": "user@example.com" + }, + "userAttributes": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + }, + { + "type": "null" + } + ] + }, + "description": "Optional user attributes as key-value pairs" + } + }, + "required": [ + "email" + ] + }, + "minItems": 1, + "maxItems": 20, + "description": "Array of users to create (1-20 users)" + } + }, + "required": [ + "users" + ] + }, + "UserGroupsGetModelRolesResponse": { + "type": "object", + "properties": { + "results": { + "type": "array", + "items": { + "$ref": "#/components/schemas/UserGroupRoleAssignmentResult" + }, + "description": "List of role assignments" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" + } + }, + "required": [ + "results", + "userGroupId" + ] + }, + "UserGroupRoleAssignmentResult": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "The base role definition name", + "example": "VIEWER" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection this role applies to" + }, + "from": { + "$ref": "#/components/schemas/UserGroupRoleOrigin" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model this role applies to" + }, + "priority": { + "type": "number", + "description": "Priority for role resolution (higher = more permissive)" + }, + "roleName": { + "type": "string", + "description": "The role name (base or custom)", + "example": "VIEWER" + } + }, + "required": [ + "baseRole", + "connectionId", + "from", + "modelId", + "priority", + "roleName" + ] + }, + "UserGroupRoleOrigin": { + "type": "object", + "properties": { + "depth": { + "type": "number", + "description": "Nesting depth of the group (0 for direct assignment)" + }, + "miniUuid": { + "type": "string", + "description": "Short identifier of the group", + "example": "abc123" + }, + "name": { + "type": "string", + "description": "Name of the group", + "example": "Engineering Team" + }, + "type": { + "type": "string", + "enum": [ + "GROUP" + ], + "description": "Role assigned to group" + } + }, + "required": [ + "depth", + "miniUuid", + "name", + "type" + ], + "description": "Origin of this role assignment" + }, + "UserGroupsAssignModelRoleResponse": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "The connection ID for this role assignment" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "The model ID for this role assignment" + }, + "roleName": { + "type": "string", + "description": "The assigned role name", + "example": "VIEWER" + }, + "userGroupId": { + "type": "string", + "description": "The user group short identifier", + "example": "abc123" + } + }, + "required": [ + "connectionId", + "modelId", + "roleName", + "userGroupId" + ] + }, + "UserGroupsAssignModelRoleBody": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID for connection-level role assignment. Required if modelId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "modelId": { + "type": "string", + "format": "uuid", + "description": "Model ID for model-level role assignment. Required if connectionId not provided.", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "roleName": { + "type": "string", + "minLength": 1, + "description": "Name of the role to assign (base or custom role)", + "example": "VIEWER" + } + }, + "required": [ + "roleName" + ] + } + }, + "parameters": {} + }, + "paths": { + "/api/v1/ai/generate-query": { + "post": { + "description": "Generate an Omni semantic query from a natural language prompt. Optionally executes the generated query and returns results. The AI analyzes the prompt, selects appropriate fields and filters from the model, and constructs a query. Requires the querier role on the target model.", + "operationId": "aiGenerateQuery", + "summary": "Generate query from natural language", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryBody" + } + } + } + }, + "responses": { + "200": { + "description": "Query generated successfully. If runQuery is true (default), includes execution results. Check the error field — a 200 response may still contain a partial error if the query was generated but execution failed. When the organization is over its AI downgrade threshold the response also carries `downgradedModelTier` naming the cheaper tier the query was generated with.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiGenerateQueryResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The prompt may be missing, the modelId may be invalid, or the AI was unable to generate a query for the given prompt.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "402": { + "description": "AI is unavailable because the organization is over its AI credit limit. The body carries the stable reason code `shutoff`.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiCreditShutoffError" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI query generation must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model or topic was not found in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/pick-topic": { + "post": { + "description": "Analyze a natural language prompt and determine which topic in the model is the best fit for answering the question. Useful as a preprocessing step before calling generate-query or submitting an AI job, especially when the user's question could relate to multiple topics.", + "operationId": "aiPickTopic", + "summary": "Pick the best topic for a prompt", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicBody" + } + } + } + }, + "responses": { + "200": { + "description": "Topic selected successfully. The returned topicId can be used as the topicName parameter in other AI endpoints.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiPickTopicResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. The prompt or modelId may be missing or malformed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. Requires the querier role on the target model and AI must be enabled for the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model was not found, or no accessible topics exist in the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/search-omni-docs": { + "post": { + "description": "Search the Omni documentation using AI to answer questions about Omni features, configuration, modeling, dashboards, and more. Sends a natural language question and returns a synthesized answer with source links to the relevant documentation pages.", + "operationId": "aiSearchOmniDocs", + "summary": "Search Omni documentation", + "tags": [ + "AI" + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsBody" + } + } + } + }, + "responses": { + "200": { + "description": "Documentation search completed successfully. Returns a synthesized answer with source links.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiSearchOmniDocsResponse" + } + } + } + }, + "400": { + "description": "Invalid request. The question may be missing or exceed the 2000 character limit.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Omni Agent is not enabled for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "500": { + "description": "AI service error." + } + } + } + }, + "/api/v1/ai/jobs": { + "post": { + "description": "Submit a new AI job for asynchronous execution. The AI will analyze the prompt, generate and execute queries against the specified model, and produce a summarized answer. Jobs are processed by a background worker and typically complete within 15–60 seconds. Use GET /api/v1/ai/jobs/{jobId} to poll for status, or configure a webhookUrl to receive a notification when the job completes. Optionally continue an existing conversation by providing a conversationId.", + "operationId": "aiJobSubmit", + "summary": "Submit an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitBody" + } + } + } + }, + "responses": { + "201": { + "description": "Job created and queued for execution. Use the returned jobId to poll for status or retrieve results.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobSubmitResponse" + } + } + } + }, + "400": { + "description": "Invalid request body. Common causes: missing or empty prompt, invalid UUID for modelId/branchId/conversationId, invalid webhook URL format.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions. The AI jobs API must be enabled for the organization, AI query generation must be enabled, and the user must have appropriate model access. User-scoped API keys cannot act on behalf of other users.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "The specified model was not found in the organization, the branchId does not belong to the specified model, or the topicName does not exist in the model (or is excluded by ai_chat_topics restrictions).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "An active job already exists for the specified conversationId. Wait for the current job to complete before submitting another job to the same conversation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}": { + "get": { + "description": "Get the current status of an AI job, including its state, progress information, and result summary. The response fields vary by state — for example, progress is only present during EXECUTING, and resultSummary is only present when COMPLETE. Poll this endpoint every 2–5 seconds until the job reaches a terminal state (COMPLETE, FAILED, or CANCELLED).", + "operationId": "aiJobStatus", + "summary": "Get AI job status", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Job status retrieved successfully. Check the state field to determine if the job is still running or has reached a terminal state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobStatusResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/cancel": { + "post": { + "description": "Request cancellation of an AI job. This endpoint is idempotent — calling it on an already-cancelled or completed job returns success with the current state. For QUEUED jobs, cancellation is immediate. For EXECUTING jobs, the worker will stop after completing its current iteration. Jobs in DELIVERING state cannot be cancelled as they are already finalizing results. Only the job owner or organization admins can cancel jobs.", + "operationId": "aiJobCancel", + "summary": "Cancel an AI job", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Cancellation request processed. The state field indicates the job's state after the attempt — CANCELLED if successful, or the current terminal state if the job had already completed.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobCancelResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Permission denied. Only the job owner or organization admins can cancel jobs.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + }, + "404": { + "description": "Job not found. The job may not exist or may belong to a different organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "409": { + "description": "Concurrent modification conflict. The job state was changed by another request. Retry the cancellation.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError409" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/result": { + "get": { + "description": "Retrieve the full result of a completed AI job, including all actions taken by the AI (queries generated, data retrieved) and the final summarized answer. Results are only available for jobs in COMPLETE state and are retained for 14 days after completion. The response is streamed directly from storage.", + "operationId": "aiJobResult", + "summary": "Get AI job result", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiJobResultResponse" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "404": { + "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + } + } + } + }, + "/api/v1/ai/jobs/{jobId}/vis": { + "get": { + "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", + "operationId": "aiJobVisualization", + "summary": "Render AI job visualization", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "The unique identifier of the AI job", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "The unique identifier of the AI job", + "name": "jobId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "content": { + "image/png": { + "schema": { + "format": "binary", + "type": "string" + } + } + } + }, + "400": { + "description": "Invalid job ID format. Must be a valid UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "404": { + "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError404" + } + } + } + }, + "422": { + "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError422" + } + } + } + } + } + } + }, + "/api/v1/ai/branding": { + "get": { + "description": "Returns the organization's AI helper branding — display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", + "operationId": "aiBranding", + "summary": "Get AI helper branding", + "tags": [ + "AI" + ], + "responses": { + "200": { + "description": "AI branding retrieved successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiBrandingResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations": { + "get": { + "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next page.", + "operationId": "aiConversationsList", + "summary": "List AI conversations", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Paginated list of conversations.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AiConversationsListResponse" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiError403" + } + } + } + } + } + } + }, + "/api/v1/ai/conversations/{conversationId}": { + "get": { + "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", + "operationId": "aiConversationDetail", + "summary": "Get AI conversation with messages", + "tags": [ + "AI" + ], + "parameters": [ + { + "schema": { "type": "string", - "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "format": "uuid" }, "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", + "name": "conversationId", "in": "path" } ], "responses": { "200": { - "description": "Full job result including the AI's actions, query results (with CSV data), and the final Markdown-formatted answer.", + "description": "Conversation with messages in chronological order.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiJobResultResponse" + "$ref": "#/components/schemas/AiConversationDetailResponse" } } } }, - "400": { - "description": "Invalid job ID format. Must be a valid UUID.", + "401": { + "description": "Missing or invalid API key.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError400" + "$ref": "#/components/schemas/ApiError401" } } } }, - "401": { - "description": "Missing or invalid API key.", + "403": { + "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError401" + "$ref": "#/components/schemas/ApiError403" } } } }, "404": { - "description": "Job not found, not in COMPLETE state, or result is no longer available (results are retained for 14 days).", + "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user — existence of another user's conversations is not disclosed.", "content": { "application/json": { "schema": { @@ -30396,525 +31092,1115 @@ } } }, - "/api/v1/ai/jobs/{jobId}/vis": { + "/api/v1/api-keys": { "get": { - "description": "Render the visualization from a completed AI job as a PNG image. The endpoint extracts the visualization configuration from the job result, loads Arrow IPC data, and renders it server-side using Vega. For style-only follow-ups (e.g., \"make it a bar chart\"), the endpoint walks back through previous jobs in the conversation to find the original query data.", - "operationId": "aiJobVisualization", - "summary": "Render AI job visualization", + "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", + "operationId": "apiKeysList", + "summary": "List API tokens", "tags": [ - "AI" + "API Tokens" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the AI job", - "example": "123e4567-e89b-12d3-a456-426614174000" + "description": "Cursor from the previous response (token UUID)" }, - "required": true, - "description": "The unique identifier of the AI job", - "name": "jobId", - "in": "path" + "required": false, + "description": "Cursor from the previous response (token UUID)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "createdAt", + "name" + ], + "default": "createdAt" + }, + "required": false, + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "personal", + "mcp" + ], + "description": "Filter by API token type. When omitted, all types are returned.", + "example": "personal" + }, + "required": false, + "description": "Filter by API token type. When omitted, all types are returned.", + "name": "type", + "in": "query" } ], "responses": { "200": { - "description": "Visualization rendered as a PNG image. The Content-Type header is image/png.", + "description": "Paginated list of API tokens", "content": { - "image/png": { + "application/json": { "schema": { - "format": "binary", - "type": "string" + "$ref": "#/components/schemas/ApiKeyListResponse" } } } }, "400": { - "description": "Invalid job ID format. Must be a valid UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError400" - } - } - } + "description": "Invalid query parameters" }, "401": { - "description": "Missing or invalid API key.", + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + } + } + } + }, + "/api/v1/api-keys/{id}": { + "get": { + "description": "Returns a single API token by id. Requires organization admin permissions.", + "operationId": "apiKeysGet", + "summary": "Get API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "responses": { + "200": { + "description": "The requested API token", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError401" + "$ref": "#/components/schemas/ApiKey" } } } }, + "400": { + "description": "Malformed `id` (must be a UUID)" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions" + }, "404": { - "description": "Job not found, not in COMPLETE state, or the apiAiVis feature flag is not enabled.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } + "description": "Token not found in this organization" + } + } + }, + "put": { + "description": "Enables or disables an API token. Requires organization admin permissions.", + "operationId": "apiKeysUpdate", + "summary": "Enable or disable an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ApiKeyUpdateBody" } } - }, - "422": { - "description": "The job completed but cannot be rendered as a visualization. Common causes: no visualization action in the job result, no Arrow IPC data available, missing summary fields, or the chart type is not renderable as an image (e.g., tables, KPIs).", + } + }, + "responses": { + "200": { + "description": "The updated API token", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiError422" + "$ref": "#/components/schemas/ApiKey" } } } + }, + "400": { + "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" + }, + "403": { + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" + } + } + }, + "delete": { + "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", + "operationId": "apiKeysDelete", + "summary": "Revoke an API token", + "tags": [ + "API Tokens" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Token UUID", + "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + }, + "required": true, + "description": "Token UUID", + "name": "id", + "in": "path" } - } - } - }, - "/api/v1/ai/branding": { - "get": { - "description": "Returns the organization's AI helper branding — display name, optional custom logo URL, and copy used on AI helper landing surfaces (headline, body, prompt placeholder). Falls back to Omni's defaults when the organization hasn't configured custom branding, so the response is always populated. Used by client apps (iOS, embeds) to render the AI helper with the org's chosen identity.", - "operationId": "aiBranding", - "summary": "Get AI helper branding", - "tags": [ - "AI" ], "responses": { "200": { - "description": "AI branding retrieved successfully.", + "description": "The token was revoked", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiBrandingResponse" + "$ref": "#/components/schemas/ApiKeyDeleteResponse" } } } }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "400": { + "description": "Malformed `id`, or missing/malformed `Authorization` header" }, "403": { - "description": "AI access is required to view AI helper branding (no model in the org grants USE_AI to the caller).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "description": "Invalid bearer token, or caller lacks organization admin permissions" + }, + "404": { + "description": "Token not found in this organization" + }, + "405": { + "description": "Method not allowed" } } } }, - "/api/v1/ai/conversations": { + "/api/v1/connections": { "get": { - "description": "List the user's recent AI conversations, ordered by most-recent activity. Each record includes the conversation id (pass it back as `conversationId` on subsequent /api/v1/ai/jobs submissions to continue the thread), an optional name, and a one-line summary of the most recent prompt for display. Paginated via opaque `pageInfo.nextCursor` — pass it back as `cursor` to fetch the next page.", - "operationId": "aiConversationsList", - "summary": "List AI conversations", + "operationId": "connectionsList", + "summary": "List connections", "tags": [ - "AI" + "Connections" ], "parameters": [ { "schema": { "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" + "description": "Filter by database name (case-insensitive contains)", + "example": "analytics" }, "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", + "description": "Filter by database name (case-insensitive contains)", + "name": "database", "in": "query" }, { "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 + "type": "string", + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "example": "snowflake,bigquery" }, "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", + "description": "Filter by dialect(s). Comma-separated list for multiple values", + "name": "dialect", + "in": "query" + }, + { + "schema": { + "type": "boolean", + "description": "Include soft-deleted connections in results", + "example": false + }, + "required": false, + "description": "Include soft-deleted connections in results", + "name": "includeDeleted", "in": "query" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Filter by connection name (case-insensitive contains)", + "example": "Production" }, "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", + "description": "Filter by connection name (case-insensitive contains)", + "name": "name", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "desc" + }, + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "database", + "dialect", + "name" + ], + "description": "Field to sort by", + "example": "name" + }, + "required": false, + "description": "Field to sort by", + "name": "sortField", "in": "query" } ], "responses": { "200": { - "description": "Paginated list of conversations.", + "description": "List of connections", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/AiConversationsListResponse" + "type": "object", + "properties": { + "connections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "description": "Whether branch environments override user attributes", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + }, + "description": "List of connections" + } + }, + "required": [ + "connections" + ], + "description": "List connections response", + "title": "ConnectionsListResponse" } } } }, "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } + "description": "Authentication required" }, "403": { - "description": "Insufficient permissions.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } + "description": "Permission denied - admin role required" } } - } - }, - "/api/v1/ai/conversations/{conversationId}": { - "get": { - "description": "Return a conversation with its full message history (alternating user / assistant turns). Used by clients (iOS app, embed widgets) to restore a prior conversation in their UI.", - "operationId": "aiConversationDetail", - "summary": "Get AI conversation with messages", + }, + "post": { + "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", + "operationId": "connectionsCreate", + "summary": "Create connection", "tags": [ - "AI" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid" - }, - "required": true, - "name": "conversationId", - "in": "path" - } + "Connections" ], - "responses": { - "200": { - "description": "Conversation with messages in chronological order.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/AiConversationDetailResponse" - } - } - } - }, - "401": { - "description": "Missing or invalid API key.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError401" - } - } - } - }, - "403": { - "description": "AI access is required to view chat conversations (no model in the org grants USE_AI to the caller).", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError403" - } - } - } - }, - "404": { - "description": "Conversation not found. User-scoped keys also get 404 (not 403) when the conversation exists but belongs to a different user — existence of another user's conversations is not disclosed.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiError404" - } + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "acceptsLicense": { + "type": "boolean", + "description": "Acceptance of the license terms. Required for Oracle connections.", + "example": true + }, + "allowsUserSpecificTimezones": { + "type": "boolean", + "default": false, + "description": "Whether to allow users to specify their own timezones", + "example": false + }, + "alwaysScopeViewNames": { + "type": "boolean", + "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", + "example": true + }, + "authenticationType": { + "type": "string", + "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", + "example": "snowflake-password" + }, + "awsRoleArn": { + "type": "string", + "description": "AWS IAM role ARN. Applicable for Athena only.", + "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" + }, + "baseRole": { + "type": "string", + "enum": [ + "NO_ACCESS", + "VIEWER", + "RESTRICTED_QUERIER", + "QUERIER", + "MODELER", + "CONNECTION_ADMIN" + ], + "description": "The default role for users accessing the connection", + "example": "QUERIER" + }, + "database": { + "type": "string", + "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", + "example": "analytics_db" + }, + "defaultSchema": { + "type": "string", + "description": "The default schema to use. Required for MSSQL.", + "example": "public" + }, + "dialect": { + "type": "string", + "enum": [ + "athena", + "bigquery", + "clickhouse", + "databricks", + "databricks_lakebase", + "exasol", + "mariadb", + "motherduck", + "mssql", + "mysql", + "oracle", + "postgres", + "redshift", + "sap_hana", + "snowflake", + "starrocks", + "trino" + ], + "description": "The database dialect", + "example": "snowflake" + }, + "enableDbSemanticLayerIntegration": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", + "example": false + }, + "enableDbSemanticLayerTopics": { + "type": "boolean", + "default": false, + "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", + "example": false + }, + "externalOauthAudience": { + "type": "string", + "description": "External OAuth audience claim. Applicable for Snowflake." + }, + "externalOauthAuthorizationUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/authorize" + }, + "externalOauthTokenUrl": { + "type": "string", + "format": "uri", + "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", + "example": "https://oauth.example.com/token" + }, + "host": { + "type": "string", + "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", + "example": "myaccount" + }, + "hostOverride": { + "type": "string", + "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", + "example": "myaccount.snowflakecomputing.com" + }, + "includeOtherCatalogs": { + "type": "string", + "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", + "example": "other_project1,other_project2" + }, + "includeSchemas": { + "type": "string", + "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", + "example": "public,analytics" + }, + "inferRelationshipsFromColumnNames": { + "type": "boolean", + "default": true, + "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", + "example": true + }, + "inferRelationshipsFromForeignKeys": { + "type": "boolean", + "default": false, + "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "example": false + }, + "maxBillingBytes": { + "type": "string", + "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", + "example": "1000000000" + }, + "name": { + "type": "string", + "description": "A descriptive name for the connection", + "example": "Production Warehouse" + }, + "oauthClientId": { + "type": "string", + "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "oauthClientSecretUnencrypted": { + "type": "string", + "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." + }, + "offloadedSchemas": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ], + "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", + "example": [ + "analytics_archive" + ] + }, + "passwordUnencrypted": { + "type": "string", + "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." + }, + "port": { + "type": "integer", + "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", + "example": 5432 + }, + "privateKey": { + "type": "string", + "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." + }, + "queryTimeoutSeconds": { + "type": "integer", + "maximum": 3600, + "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", + "example": 900 + }, + "queryTimezone": { + "type": "string", + "description": "The timezone to use for queries", + "example": "NONE" + }, + "region": { + "type": "string", + "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", + "example": "us-east-1" + }, + "scratchSchema": { + "type": "string", + "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", + "example": "omni_scratch" + }, + "systemTimezone": { + "type": "string", + "description": "The timezone to use for the system", + "example": "UTC" + }, + "trustServerCertificate": { + "type": "boolean", + "default": false, + "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", + "example": false + }, + "useMachineAuth": { + "type": "boolean", + "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "example": false + }, + "username": { + "type": "string", + "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", + "example": "analytics_user" + }, + "warehouse": { + "type": "string", + "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path).", + "example": "COMPUTE_WH" + } + }, + "required": [ + "dialect", + "name", + "passwordUnencrypted" + ], + "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", + "title": "ConnectionsCreateBody" } } } - } - } - }, - "/api/v1/api-keys": { - "get": { - "description": "Returns all API tokens in the organization, including organization-level keys, personal access tokens, and MCP OAuth grants. Secrets are never returned. Requires organization admin permissions.", - "operationId": "apiKeysList", - "summary": "List API tokens", - "tags": [ - "API Tokens" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Cursor from the previous response (token UUID)" - }, - "required": false, - "description": "Cursor from the previous response (token UUID)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "createdAt", - "name" - ], - "default": "createdAt" - }, - "required": false, - "name": "sortField", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "organization", - "personal", - "mcp" - ], - "description": "Filter by API token type. When omitted, all types are returned.", - "example": "personal" - }, - "required": false, - "description": "Filter by API token type. When omitted, all types are returned.", - "name": "type", - "in": "query" - } - ], + }, "responses": { - "200": { - "description": "Paginated list of API tokens", + "201": { + "description": "Connection created successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyListResponse" + "type": "object", + "properties": { + "data": { + "type": "string", + "format": "uuid", + "description": "Created connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "data", + "success" + ], + "description": "Create connection response", + "title": "ConnectionsCreateResponse" } } } }, "400": { - "description": "Invalid query parameters" + "description": "Invalid request body or dialect" }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions" + "description": "Permission denied - admin role required" } } } }, - "/api/v1/api-keys/{id}": { + "/api/v1/connections/{id}": { "get": { - "description": "Returns a single API token by id. Requires organization admin permissions.", - "operationId": "apiKeysGet", - "summary": "Get API token", - "tags": [ - "API Tokens" - ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" - }, - "required": true, - "description": "Token UUID", - "name": "id", - "in": "path" - } - ], - "responses": { - "200": { - "description": "The requested API token", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKey" - } - } - } - }, - "400": { - "description": "Malformed `id` (must be a UUID)" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Insufficient permissions" - }, - "404": { - "description": "Token not found in this organization" - } - } - }, - "put": { - "description": "Enables or disables an API token. Requires organization admin permissions.", - "operationId": "apiKeysUpdate", - "summary": "Enable or disable an API token", + "description": "Fetch a single connection by ID.", + "operationId": "connectionsGet", + "summary": "Get connection", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", + "description": "Connection ID", "name": "id", "in": "path" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/ApiKeyUpdateBody" - } - } - } - }, "responses": { "200": { - "description": "The updated API token", + "description": "Connection object", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKey" + "type": "object", + "properties": { + "connection": { + "type": "object", + "properties": { + "baseRole": { + "type": [ + "string", + "null" + ], + "description": "Default role for users on this connection", + "example": "QUERIER" + }, + "branchConnectionEnvironmentOverridesUserAttr": { + "type": [ + "boolean", + "null" + ], + "description": "Whether branch environments override user attributes", + "example": false + }, + "createdAt": { + "type": "string", + "description": "Timestamp when connection was created (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "database": { + "type": [ + "string", + "null" + ], + "description": "Database name", + "example": "analytics_db" + }, + "defaultSchema": { + "type": [ + "string", + "null" + ], + "description": "Default schema for the connection", + "example": "public" + }, + "deletedAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when connection was deleted (ISO 8601)", + "example": null + }, + "dialect": { + "type": "string", + "enum": [ + "snowflake", + "bigquery", + "redshift", + "postgres", + "mysql", + "mariadb", + "databricks", + "databricks_lakebase", + "trino", + "athena", + "duckdb", + "motherduck", + "sqlserver", + "clickhouse", + "singlestore" + ], + "description": "Database dialect type", + "example": "snowflake" + }, + "environmentConnectionSwitchesSchemaModel": { + "type": [ + "boolean", + "null" + ], + "description": "Whether environment connections switch schema model", + "example": false + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection identifier", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "name": { + "type": "string", + "description": "Connection display name", + "example": "Production Snowflake" + }, + "updatedAt": { + "type": "string", + "description": "Timestamp when connection was last updated (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "userAttributeNameForConnectionEnvironments": { + "type": [ + "string", + "null" + ], + "description": "User attribute name used for connection environments", + "example": "region" + }, + "userAttributeValuesForDefaultEnvironment": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default user attribute values for the base environment", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "baseRole", + "branchConnectionEnvironmentOverridesUserAttr", + "createdAt", + "database", + "defaultSchema", + "deletedAt", + "dialect", + "environmentConnectionSwitchesSchemaModel", + "id", + "name", + "updatedAt", + "userAttributeNameForConnectionEnvironments", + "userAttributeValuesForDefaultEnvironment" + ], + "description": "Connection object", + "title": "Connection" + } + }, + "required": [ + "connection" + ], + "description": "Get connection response", + "title": "ConnectionsGetResponse" } } } }, - "400": { - "description": "Invalid body, malformed `id`, or missing/malformed `Authorization` header" + "401": { + "description": "Authentication required" }, "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" + "description": "Permission denied — caller lacks READ on the connection" }, "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" + "description": "Connection does not exist" } } }, - "delete": { - "description": "Revokes an API token by permanently deleting it. Works for all token types. Requires organization admin permissions.", - "operationId": "apiKeysDelete", - "summary": "Revoke an API token", + "patch": { + "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", + "operationId": "connectionsUpdate", + "summary": "Update connection", "tags": [ - "API Tokens" + "Connections" ], "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Token UUID", - "example": "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Token UUID", + "description": "Connection ID", "name": "id", "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseRole": { + "type": "string", + "description": "Default role to assign to this connection", + "example": "QUERIER" + }, + "environmentUserAttribute": { + "type": [ + "object", + "null" + ], + "properties": { + "attributeName": { + "type": "string", + "description": "Name of the user attribute for environment selection", + "example": "region" + }, + "defaultValues": { + "type": [ + "array", + "null" + ], + "items": { + "type": "string" + }, + "description": "Default values for the user attribute", + "example": [ + "us-east", + "us-west" + ] + } + }, + "required": [ + "attributeName", + "defaultValues" + ], + "description": "User attribute settings for connection environments" + }, + "passwordUnencrypted": { + "type": "string", + "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." + }, + "privateKey": { + "type": "string", + "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." + } + }, + "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", + "title": "ConnectionsUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "The token was revoked", + "description": "Connection updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ApiKeyDeleteResponse" + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing what was updated", + "example": "Updated connection default role." + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "Update connection response", + "title": "ConnectionsUpdateResponse" } } } }, "400": { - "description": "Malformed `id`, or missing/malformed `Authorization` header" + "description": "Invalid request body - at least one field must be provided" + }, + "401": { + "description": "Authentication required" }, "403": { - "description": "Invalid bearer token, or caller lacks organization admin permissions" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Token not found in this organization" - }, - "405": { - "description": "Method not allowed" + "description": "Connection not found" } } - } - }, - "/api/v1/connections": { - "get": { - "operationId": "connectionsList", - "summary": "List connections", + }, + "delete": { + "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", + "operationId": "connectionsDelete", + "summary": "Delete connection", "tags": [ "Connections" ], @@ -30922,232 +32208,41 @@ { "schema": { "type": "string", - "description": "Filter by database name (case-insensitive contains)", - "example": "analytics" - }, - "required": false, - "description": "Filter by database name (case-insensitive contains)", - "name": "database", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "example": "snowflake,bigquery" - }, - "required": false, - "description": "Filter by dialect(s). Comma-separated list for multiple values", - "name": "dialect", - "in": "query" - }, - { - "schema": { - "type": "boolean", - "description": "Include soft-deleted connections in results", - "example": false - }, - "required": false, - "description": "Include soft-deleted connections in results", - "name": "includeDeleted", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Filter by connection name (case-insensitive contains)", - "example": "Production" - }, - "required": false, - "description": "Filter by connection name (case-insensitive contains)", - "name": "name", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "description": "Sort direction", - "example": "desc" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "database", - "dialect", - "name" - ], - "description": "Field to sort by", - "example": "name" + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" + "required": true, + "description": "Connection ID", + "name": "id", + "in": "path" } - ], - "responses": { - "200": { - "description": "List of connections", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connections": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseRole": { - "type": [ - "string", - "null" - ], - "description": "Default role for users on this connection", - "example": "QUERIER" - }, - "branchConnectionEnvironmentOverridesUserAttr": { - "type": [ - "boolean", - "null" - ], - "description": "Whether branch environments override user attributes", - "example": false - }, - "createdAt": { - "type": "string", - "description": "Timestamp when connection was created (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "database": { - "type": [ - "string", - "null" - ], - "description": "Database name", - "example": "analytics_db" - }, - "defaultSchema": { - "type": [ - "string", - "null" - ], - "description": "Default schema for the connection", - "example": "public" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when connection was deleted (ISO 8601)", - "example": null - }, - "dialect": { - "type": "string", - "enum": [ - "snowflake", - "bigquery", - "redshift", - "postgres", - "mysql", - "mariadb", - "databricks", - "databricks_lakebase", - "trino", - "athena", - "duckdb", - "motherduck", - "sqlserver", - "clickhouse", - "singlestore" - ], - "description": "Database dialect type", - "example": "snowflake" - }, - "environmentConnectionSwitchesSchemaModel": { - "type": [ - "boolean", - "null" - ], - "description": "Whether environment connections switch schema model", - "example": false - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection identifier", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "name": { - "type": "string", - "description": "Connection display name", - "example": "Production Snowflake" - }, - "updatedAt": { - "type": "string", - "description": "Timestamp when connection was last updated (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "userAttributeNameForConnectionEnvironments": { - "type": [ - "string", - "null" - ], - "description": "User attribute name used for connection environments", - "example": "region" - }, - "userAttributeValuesForDefaultEnvironment": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default user attribute values for the base environment", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "baseRole", - "branchConnectionEnvironmentOverridesUserAttr", - "createdAt", - "database", - "defaultSchema", - "deletedAt", - "dialect", - "environmentConnectionSwitchesSchemaModel", - "id", - "name", - "updatedAt", - "userAttributeNameForConnectionEnvironments", - "userAttributeValuesForDefaultEnvironment" - ], - "description": "Connection object", - "title": "Connection" - }, - "description": "List of connections" + ], + "responses": { + "200": { + "description": "Connection moved to trash", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Status message describing the result", + "example": "Connection moved to trash." + }, + "success": { + "type": "boolean", + "description": "True when the connection was archived", + "example": true } }, "required": [ - "connections" + "message", + "success" ], - "description": "List connections response", - "title": "ConnectionsListResponse" + "description": "Archive connection response", + "title": "ConnectionsDeleteResponse" } } } @@ -31156,276 +32251,332 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + }, + "410": { + "description": "Connection has already been archived" } } - }, - "post": { - "description": "Create a new database connection. The request body varies by dialect - see dialect-specific documentation for required fields.", - "operationId": "connectionsCreate", - "summary": "Create connection", + } + }, + "/api/v1/connections/{connectionId}/dbt": { + "get": { + "operationId": "connectionsDbtGet", + "summary": "Get dbt configuration", "tags": [ "Connections" ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "acceptsLicense": { - "type": "boolean", - "description": "Acceptance of the license terms. Required for Oracle connections.", - "example": true - }, - "allowsUserSpecificTimezones": { - "type": "boolean", - "default": false, - "description": "Whether to allow users to specify their own timezones", - "example": false - }, - "alwaysScopeViewNames": { - "type": "boolean", - "description": "Whether to always include schema (and catalog) prefixes in generated view names, even for tables in the default schema. Defaults to true for dialects that support multiple catalogs, false otherwise.", - "example": true - }, - "authenticationType": { - "type": "string", - "description": "Authentication type. Applicable for BigQuery, MSSQL, Snowflake, Databricks, and Athena.", - "example": "snowflake-password" - }, - "awsRoleArn": { - "type": "string", - "description": "AWS IAM role ARN. Applicable for Athena only.", - "example": "arn:aws:iam::123456789012:role/OmniAthenaRole" - }, - "baseRole": { - "type": "string", - "enum": [ - "NO_ACCESS", - "VIEWER", - "RESTRICTED_QUERIER", - "QUERIER", - "MODELER", - "CONNECTION_ADMIN" - ], - "description": "The default role for users accessing the connection", - "example": "QUERIER" - }, - "database": { - "type": "string", - "description": "The default database/catalog to connect to. For BigQuery, this is the project ID. For Athena, this is the data catalog.", - "example": "analytics_db" - }, - "defaultSchema": { - "type": "string", - "description": "The default schema to use. Required for MSSQL.", - "example": "public" - }, - "dialect": { - "type": "string", - "enum": [ - "athena", - "bigquery", - "clickhouse", - "databricks", - "databricks_lakebase", - "exasol", - "mariadb", - "motherduck", - "mssql", - "mysql", - "oracle", - "postgres", - "redshift", - "sap_hana", - "snowflake", - "starrocks", - "trino" - ], - "description": "The database dialect", - "example": "snowflake" - }, - "enableDbSemanticLayerIntegration": { - "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer integration. Applicable for Snowflake and Databricks.", - "example": false - }, - "enableDbSemanticLayerTopics": { + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "responses": { + "200": { + "description": "dbt configuration for the connection", + "content": { + "application/json": { + "schema": { + "anyOf": [ + { + "type": "object", + "properties": { + "autogenRelationships": { + "type": "boolean", + "description": "Whether relationships are auto-generated from dbt", + "example": true + }, + "branch": { + "type": "string", + "description": "Git branch name", + "example": "main" + }, + "dbtVersion": { + "type": "string", + "description": "dbt version being used", + "example": "Auto" + }, + "enableSemanticLayer": { + "type": "boolean", + "description": "Whether the dbt semantic layer integration is enabled", + "example": false + }, + "enableVirtualSchemas": { + "type": "boolean", + "description": "Whether virtual schemas are enabled", + "example": false + }, + "projectRootPath": { + "type": [ + "string", + "null" + ], + "description": "Path to dbt project root", + "example": "dbt_project" + }, + "sshUrl": { + "type": "string", + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" + }, + "supportsDbt": { + "type": "boolean", + "enum": [ + true + ], + "description": "Indicates dbt is supported and configured", + "example": true + } + }, + "required": [ + "autogenRelationships", + "branch", + "dbtVersion", + "enableSemanticLayer", + "enableVirtualSchemas", + "projectRootPath", + "sshUrl", + "supportsDbt" + ], + "description": "dbt repository configuration response", + "title": "DbtConfiguredResponse" + }, + { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Message explaining dbt status", + "example": "dbt not configured for this connection" + }, + "supportsDbt": { + "type": "boolean", + "description": "Whether the connection dialect supports dbt", + "example": true + } + }, + "required": [ + "message", + "supportsDbt" + ], + "description": "Response when dbt is not configured", + "title": "DbtNotConfiguredResponse" + } + ], + "description": "dbt configuration response", + "title": "ConnectionsDbtGetResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "put": { + "operationId": "connectionsDbtUpdate", + "summary": "Update dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "autogenRelationships": { "type": "boolean", - "default": false, - "description": "Enable the dialect-native semantic layer topics. Applicable for Snowflake and Databricks.", - "example": false - }, - "externalOauthAudience": { - "type": "string", - "description": "External OAuth audience claim. Applicable for Snowflake." - }, - "externalOauthAuthorizationUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth authorization URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/authorize" - }, - "externalOauthTokenUrl": { - "type": "string", - "format": "uri", - "description": "External OAuth token URL (must be HTTPS). Applicable for Snowflake.", - "example": "https://oauth.example.com/token" - }, - "host": { - "type": "string", - "description": "The hostname or IP address of the database server. For Snowflake, provide only the account identifier.", - "example": "myaccount" - }, - "hostOverride": { - "type": "string", - "description": "Custom Snowflake host (when not using the account identifier). Mutually exclusive with `host`.", - "example": "myaccount.snowflakecomputing.com" - }, - "includeOtherCatalogs": { - "type": "string", - "description": "Comma-separated list of other catalogs/databases to include. Only applicable for databases that support multi-catalog queries.", - "example": "other_project1,other_project2" + "description": "Automatically generate relationships from dbt", + "example": true }, - "includeSchemas": { + "branch": { "type": "string", - "description": "Comma-separated list of schemas to include. Leave empty to include all schemas.", - "example": "public,analytics" + "minLength": 1, + "description": "Git branch name", + "example": "main" }, - "inferRelationshipsFromColumnNames": { - "type": "boolean", - "default": true, - "description": "Whether to infer relationships from column-name conventions during schema refresh. Defaults to true.", - "example": true + "dbtVersion": { + "type": [ + "string", + "null" + ], + "description": "dbt version to use. Supported: Auto, 1.10, 1.11", + "example": "1.11" }, - "inferRelationshipsFromForeignKeys": { + "enableSemanticLayer": { "type": "boolean", "default": false, - "description": "Whether to infer relationships from declared foreign keys during schema refresh. Currently honored for Postgres and Snowflake.", + "description": "Enable dbt semantic layer integration", "example": false }, - "maxBillingBytes": { - "type": "string", - "description": "Maximum bytes that can be billed for a BigQuery query. Applicable for BigQuery only.", - "example": "1000000000" - }, - "name": { - "type": "string", - "description": "A descriptive name for the connection", - "example": "Production Warehouse" - }, - "oauthClientId": { - "type": "string", - "description": "OAuth client ID for admin schema refresh. Applicable for Snowflake and Databricks." - }, - "oauthClientSecretUnencrypted": { - "type": "string", - "description": "OAuth client secret for admin schema refresh. Applicable for Snowflake and Databricks." + "enableVirtualSchemas": { + "type": "boolean", + "description": "Enable virtual schemas from dbt", + "example": false }, - "offloadedSchemas": { + "projectRootPath": { "anyOf": [ { - "type": "string" + "type": "string", + "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" }, { - "type": "array", - "items": { - "type": "string" - } + "type": "string", + "enum": [ + "" + ] + }, + { + "type": [ + "object", + "null" + ], + "enum": [ + null + ] + }, + { + "type": "null" } ], - "description": "Schemas whose tables should be queried via the offloaded engine. Accepts a comma-separated string or an array of schema names.", - "example": [ - "analytics_archive" - ] - }, - "passwordUnencrypted": { - "type": "string", - "description": "The password to authenticate with. For BigQuery, this must be the JSON service account key file content. For Snowflake with keypair authentication, this can be omitted." - }, - "port": { - "type": "integer", - "description": "The port number for the database connection. Not required for Snowflake, MotherDuck, BigQuery, Databricks, and Athena.", - "example": 5432 - }, - "privateKey": { - "type": "string", - "description": "An RSA key for keypair authentication. Omni will automatically add PEM headers if none are provided. Applicable for Snowflake only." - }, - "queryTimeoutSeconds": { - "type": "integer", - "maximum": 3600, - "description": "The timeout in seconds for queries. Maximum value is 3600 (1 hour). Only applicable for databases that support query timeouts.", - "example": 900 - }, - "queryTimezone": { - "type": "string", - "description": "The timezone to use for queries", - "example": "NONE" - }, - "region": { - "type": "string", - "description": "Required for BigQuery and Athena connections. For BigQuery, specify a region like \"us\". For Athena, specify an AWS region like \"us-east-1\".", - "example": "us-east-1" - }, - "scratchSchema": { - "type": "string", - "description": "Schema to use for data input (upload) tables. If not specified, a suitable default will be chosen.", - "example": "omni_scratch" - }, - "systemTimezone": { - "type": "string", - "description": "The timezone to use for the system", - "example": "UTC" + "default": null, + "description": "Path to dbt project root within repository", + "example": "dbt_project" }, - "trustServerCertificate": { + "rotateKeys": { "type": "boolean", "default": false, - "description": "Whether to trust the server certificate. Applicable for MSSQL, Exasol, ClickHouse, Trino, and SAP HANA.", - "example": false - }, - "useMachineAuth": { - "type": "boolean", - "description": "Whether to authenticate using machine credentials (OAuth M2M). Applicable for Athena and Databricks.", + "description": "Rotate SSH deploy keys", "example": false }, - "username": { - "type": "string", - "description": "The username to authenticate with. For BigQuery, this is the client email from the service account.", - "example": "analytics_user" - }, - "warehouse": { + "sshUrl": { "type": "string", - "description": "Required for Snowflake (specify the warehouse) and Databricks (specify the HTTP path).", - "example": "COMPUTE_WH" + "minLength": 1, + "description": "SSH URL for git repository", + "example": "git@github.com:org/repo.git" } }, "required": [ - "dialect", - "name", - "passwordUnencrypted" + "autogenRelationships", + "branch", + "enableVirtualSchemas", + "sshUrl" ], - "description": "Request body for creating a database connection. Required fields: dialect, name, passwordUnencrypted. Additional fields may be required depending on the dialect.", - "title": "ConnectionsCreateBody" + "description": "dbt repository configuration", + "title": "ConnectionsDbtUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "dbt configuration updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "message": { + "type": "string", + "description": "Success message", + "example": "dbt configuration updated successfully" + }, + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "message", + "success" + ], + "description": "dbt update response", + "title": "ConnectionsDbtUpdateResponse" + } } } + }, + "400": { + "description": "Invalid request body or validation error" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found" + } + } + }, + "delete": { + "operationId": "connectionsDbtDelete", + "summary": "Delete dbt configuration", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" } - }, + ], "responses": { - "201": { - "description": "Connection created successfully", + "200": { + "description": "dbt configuration deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "data": { + "message": { "type": "string", - "format": "uuid", - "description": "Created connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Success message", + "example": "dbt repository unlinked successfully" }, "success": { "type": "boolean", @@ -31434,32 +32585,32 @@ } }, "required": [ - "data", + "message", "success" ], - "description": "Create connection response", - "title": "ConnectionsCreateResponse" + "description": "dbt delete response", + "title": "ConnectionsDbtDeleteResponse" } } } }, - "400": { - "description": "Invalid request body or dialect" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection not found or dbt not configured" } } } }, - "/api/v1/connections/{id}": { + "/api/v1/connections/{connectionId}/dbt/environments": { "get": { - "description": "Fetch a single connection by ID.", - "operationId": "connectionsGet", - "summary": "Get connection", + "description": "List all dbt environments for a connection.", + "operationId": "connectionsDbtEnvironmentsList", + "summary": "List dbt environments", "tags": [ "Connections" ], @@ -31473,159 +32624,73 @@ }, "required": true, "description": "Connection ID", - "name": "id", + "name": "connectionId", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "desc", + "description": "Sort direction for results", + "example": "desc" + }, + "required": false, + "description": "Sort direction for results", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "name" + ], + "default": "name", + "description": "Field to sort results by", + "example": "name" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" } ], - "responses": { - "200": { - "description": "Connection object", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connection": { - "type": "object", - "properties": { - "baseRole": { - "type": [ - "string", - "null" - ], - "description": "Default role for users on this connection", - "example": "QUERIER" - }, - "branchConnectionEnvironmentOverridesUserAttr": { - "type": [ - "boolean", - "null" - ], - "description": "Whether branch environments override user attributes", - "example": false - }, - "createdAt": { - "type": "string", - "description": "Timestamp when connection was created (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "database": { - "type": [ - "string", - "null" - ], - "description": "Database name", - "example": "analytics_db" - }, - "defaultSchema": { - "type": [ - "string", - "null" - ], - "description": "Default schema for the connection", - "example": "public" - }, - "deletedAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when connection was deleted (ISO 8601)", - "example": null - }, - "dialect": { - "type": "string", - "enum": [ - "snowflake", - "bigquery", - "redshift", - "postgres", - "mysql", - "mariadb", - "databricks", - "databricks_lakebase", - "trino", - "athena", - "duckdb", - "motherduck", - "sqlserver", - "clickhouse", - "singlestore" - ], - "description": "Database dialect type", - "example": "snowflake" - }, - "environmentConnectionSwitchesSchemaModel": { - "type": [ - "boolean", - "null" - ], - "description": "Whether environment connections switch schema model", - "example": false - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection identifier", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "name": { - "type": "string", - "description": "Connection display name", - "example": "Production Snowflake" - }, - "updatedAt": { - "type": "string", - "description": "Timestamp when connection was last updated (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "userAttributeNameForConnectionEnvironments": { - "type": [ - "string", - "null" - ], - "description": "User attribute name used for connection environments", - "example": "region" - }, - "userAttributeValuesForDefaultEnvironment": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default user attribute values for the base environment", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "baseRole", - "branchConnectionEnvironmentOverridesUserAttr", - "createdAt", - "database", - "defaultSchema", - "deletedAt", - "dialect", - "environmentConnectionSwitchesSchemaModel", - "id", - "name", - "updatedAt", - "userAttributeNameForConnectionEnvironments", - "userAttributeValuesForDefaultEnvironment" - ], - "description": "Connection object", - "title": "Connection" - } - }, - "required": [ - "connection" - ], - "description": "Get connection response", - "title": "ConnectionsGetResponse" + "responses": { + "200": { + "description": "List of dbt environments", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentListResponse" } } } @@ -31634,17 +32699,17 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied — caller lacks READ on the connection" + "description": "Permission denied or connection does not support dbt" }, "404": { - "description": "Connection does not exist" + "description": "Connection not found" } } }, - "patch": { - "description": "Update connection settings including base role, environment user attributes, and credentials.\n\nCredential fields:\n- `passwordUnencrypted`: Update password (all dialects) or service account JSON (BigQuery)\n- `privateKey`: Add/rotate RSA keypair for Snowflake keypair authentication\n\nNote: Credentials are encrypted at rest and never returned in API responses.", - "operationId": "connectionsUpdate", - "summary": "Update connection", + "post": { + "description": "Create a new dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsCreate", + "summary": "Create dbt environment", "tags": [ "Connections" ], @@ -31658,115 +32723,59 @@ }, "required": true, "description": "Connection ID", - "name": "id", + "name": "connectionId", "in": "path" } ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "baseRole": { - "type": "string", - "description": "Default role to assign to this connection", - "example": "QUERIER" - }, - "environmentUserAttribute": { - "type": [ - "object", - "null" - ], - "properties": { - "attributeName": { - "type": "string", - "description": "Name of the user attribute for environment selection", - "example": "region" - }, - "defaultValues": { - "type": [ - "array", - "null" - ], - "items": { - "type": "string" - }, - "description": "Default values for the user attribute", - "example": [ - "us-east", - "us-west" - ] - } - }, - "required": [ - "attributeName", - "defaultValues" - ], - "description": "User attribute settings for connection environments" - }, - "passwordUnencrypted": { - "type": "string", - "description": "New password or service account key. For BigQuery, this must be the JSON service account key file content." - }, - "privateKey": { - "type": "string", - "description": "RSA private key for keypair authentication (Snowflake only). Must be PEM-encoded PKCS#8 format, minimum 2048-bit." - } - }, - "description": "Request body for updating connection attributes and credentials. At least one field must be provided.", - "title": "ConnectionsUpdateBody" + "$ref": "#/components/schemas/DbtEnvironmentCreateBody" } } } }, "responses": { - "200": { - "description": "Connection updated successfully", + "201": { + "description": "dbt environment created successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Status message describing what was updated", - "example": "Updated connection default role." + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + { + "description": "Created dbt environment", + "title": "DbtEnvironmentCreateResponse" } - }, - "required": [ - "message", - "success" - ], - "description": "Update connection response", - "title": "ConnectionsUpdateResponse" + ] } } } }, "400": { - "description": "Invalid request body - at least one field must be provided" + "description": "Invalid request body" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied or connection does not support dbt" }, "404": { "description": "Connection not found" } } - }, - "delete": { - "description": "Archive a connection (move to trash). Archived connections can be restored from the trash in the connection settings UI.\n\nA connection that is already archived returns 410.", - "operationId": "connectionsDelete", - "summary": "Delete connection", + } + }, + "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { + "put": { + "description": "Update an existing dbt environment for a connection.", + "operationId": "connectionsDbtEnvironmentsUpdate", + "summary": "Update dbt environment", "tags": [ "Connections" ], @@ -31780,187 +32789,69 @@ }, "required": true, "description": "Connection ID", - "name": "id", + "name": "connectionId", "in": "path" - } - ], - "responses": { - "200": { - "description": "Connection moved to trash", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Status message describing the result", - "example": "Connection moved to trash." - }, - "success": { - "type": "boolean", - "description": "True when the connection was archived", - "example": true - } - }, - "required": [ - "message", - "success" - ], - "description": "Archive connection response", - "title": "ConnectionsDeleteResponse" - } - } - } - }, - "401": { - "description": "Authentication required" }, - "403": { - "description": "Permission denied - connection admin role required" - }, - "404": { - "description": "Connection not found" - }, - "410": { - "description": "Connection has already been archived" - } - } - } - }, - "/api/v1/connections/{connectionId}/dbt": { - "get": { - "operationId": "connectionsDbtGet", - "summary": "Get dbt configuration", - "tags": [ - "Connections" - ], - "parameters": [ { "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Environment ID", + "name": "environmentId", "in": "path" } ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "dbt configuration for the connection", + "description": "dbt environment updated successfully", "content": { "application/json": { "schema": { - "anyOf": [ - { - "type": "object", - "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Whether relationships are auto-generated from dbt", - "example": true - }, - "branch": { - "type": "string", - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": "string", - "description": "dbt version being used", - "example": "Auto" - }, - "enableSemanticLayer": { - "type": "boolean", - "description": "Whether the dbt semantic layer integration is enabled", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Whether virtual schemas are enabled", - "example": false - }, - "projectRootPath": { - "type": [ - "string", - "null" - ], - "description": "Path to dbt project root", - "example": "dbt_project" - }, - "sshUrl": { - "type": "string", - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" - }, - "supportsDbt": { - "type": "boolean", - "enum": [ - true - ], - "description": "Indicates dbt is supported and configured", - "example": true - } - }, - "required": [ - "autogenRelationships", - "branch", - "dbtVersion", - "enableSemanticLayer", - "enableVirtualSchemas", - "projectRootPath", - "sshUrl", - "supportsDbt" - ], - "description": "dbt repository configuration response", - "title": "DbtConfiguredResponse" + "allOf": [ + { + "$ref": "#/components/schemas/DbtEnvironmentItem" }, { - "type": "object", - "properties": { - "message": { - "type": "string", - "description": "Message explaining dbt status", - "example": "dbt not configured for this connection" - }, - "supportsDbt": { - "type": "boolean", - "description": "Whether the connection dialect supports dbt", - "example": true - } - }, - "required": [ - "message", - "supportsDbt" - ], - "description": "Response when dbt is not configured", - "title": "DbtNotConfiguredResponse" + "description": "Updated dbt environment", + "title": "DbtEnvironmentUpdateResponse" } - ], - "description": "dbt configuration response", - "title": "ConnectionsDbtGetResponse" + ] } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied or connection does not support dbt" }, "404": { - "description": "Connection not found" + "description": "Connection or environment not found" } } }, - "put": { - "operationId": "connectionsDbtUpdate", - "summary": "Update dbt configuration", + "delete": { + "description": "Delete a dbt environment from a connection.", + "operationId": "connectionsDbtEnvironmentsDelete", + "summary": "Delete dbt environment", "tags": [ "Connections" ], @@ -31976,130 +32867,154 @@ "description": "Connection ID", "name": "connectionId", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Environment ID", + "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + }, + "required": true, + "description": "Environment ID", + "name": "environmentId", + "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "autogenRelationships": { - "type": "boolean", - "description": "Automatically generate relationships from dbt", - "example": true - }, - "branch": { - "type": "string", - "minLength": 1, - "description": "Git branch name", - "example": "main" - }, - "dbtVersion": { - "type": [ - "string", - "null" - ], - "description": "dbt version to use. Supported: Auto, 1.10, 1.11", - "example": "1.11" - }, - "enableSemanticLayer": { - "type": "boolean", - "default": false, - "description": "Enable dbt semantic layer integration", - "example": false - }, - "enableVirtualSchemas": { - "type": "boolean", - "description": "Enable virtual schemas from dbt", - "example": false - }, - "projectRootPath": { - "anyOf": [ - { - "type": "string", - "pattern": "^(?!\\/)(?!.*\\.\\.)[\\w ./-]+$" - }, - { - "type": "string", - "enum": [ - "" - ] - }, - { - "type": [ - "object", - "null" - ], - "enum": [ - null - ] - }, - { - "type": "null" - } - ], - "default": null, - "description": "Path to dbt project root within repository", - "example": "dbt_project" - }, - "rotateKeys": { - "type": "boolean", - "default": false, - "description": "Rotate SSH deploy keys", - "example": false - }, - "sshUrl": { - "type": "string", - "minLength": 1, - "description": "SSH URL for git repository", - "example": "git@github.com:org/repo.git" - } - }, - "required": [ - "autogenRelationships", - "branch", - "enableVirtualSchemas", - "sshUrl" - ], - "description": "dbt repository configuration", - "title": "ConnectionsDbtUpdateBody" + "responses": { + "200": { + "description": "dbt environment deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + } } } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied or connection does not support dbt" + }, + "404": { + "description": "Connection or environment not found" } - }, + } + } + }, + "/api/v1/connections/{connectionId}/schedules": { + "get": { + "operationId": "connectionsSchedulesList", + "summary": "List schema refresh schedules", + "tags": [ + "Connections" + ], + "parameters": [ + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Connection ID", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "required": true, + "description": "Connection ID", + "name": "connectionId", + "in": "path" + } + ], "responses": { "200": { - "description": "dbt configuration updated successfully", + "description": "List of schema refresh schedules", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { - "type": "string", - "description": "Success message", - "example": "dbt configuration updated successfully" - }, - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + "schedules": { + "type": "array", + "items": { + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Schema refresh schedule object", + "title": "ConnectionSchedule" + }, + "description": "List of schema refresh schedules" } }, "required": [ - "message", - "success" + "schedules" ], - "description": "dbt update response", - "title": "ConnectionsDbtUpdateResponse" + "description": "List schedules response", + "title": "ConnectionsSchedulesListResponse" } } } }, - "400": { - "description": "Invalid request body or validation error" - }, "401": { "description": "Authentication required" }, @@ -32111,9 +33026,9 @@ } } }, - "delete": { - "operationId": "connectionsDbtDelete", - "summary": "Delete dbt configuration", + "post": { + "operationId": "connectionsSchedulesCreate", + "summary": "Create schema refresh schedule", "tags": [ "Connections" ], @@ -32131,35 +33046,118 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "hardRefresh": { + "type": "boolean", + "default": false, + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for creating a schema refresh schedule", + "title": "ConnectionsSchedulesCreateBody" + } + } + } + }, "responses": { - "200": { - "description": "dbt configuration deleted successfully", + "201": { + "description": "Schema refresh schedule created successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "message": { + "connectionId": { "type": "string", - "description": "Success message", - "example": "dbt repository unlinked successfully" + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "success": { + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { "type": "boolean", - "description": "Whether the operation succeeded", - "example": true + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" } }, "required": [ - "message", - "success" + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" ], - "description": "dbt delete response", - "title": "ConnectionsDbtDeleteResponse" + "description": "Created schedule response", + "title": "ConnectionsSchedulesCreateResponse" } } } }, + "400": { + "description": "Invalid cron expression or timezone" + }, "401": { "description": "Authentication required" }, @@ -32167,16 +33165,15 @@ "description": "Permission denied - connection admin role required" }, "404": { - "description": "Connection not found or dbt not configured" + "description": "Connection not found" } } } }, - "/api/v1/connections/{connectionId}/dbt/environments": { + "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { "get": { - "description": "List all dbt environments for a connection.", - "operationId": "connectionsDbtEnvironmentsList", - "summary": "List dbt environments", + "operationId": "connectionsSchedulesGet", + "summary": "Get schema refresh schedule", "tags": [ "Connections" ], @@ -32196,67 +33193,88 @@ { "schema": { "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "desc", - "description": "Sort direction for results", - "example": "desc" - }, - "required": false, - "description": "Sort direction for results", - "name": "sortDirection", - "in": "query" - }, - { - "schema": { - "type": "string", - "enum": [ - "name" - ], - "default": "name", - "description": "Field to sort results by", - "example": "name" + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" } ], "responses": { "200": { - "description": "List of dbt environments", + "description": "Schema refresh schedule details", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DbtEnvironmentListResponse" + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + } + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Get schedule response", + "title": "ConnectionsSchedulesGetResponse" } } } @@ -32265,17 +33283,16 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied or connection does not support dbt" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection or schedule not found" } } }, - "post": { - "description": "Create a new dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsCreate", - "summary": "Create dbt environment", + "put": { + "operationId": "connectionsSchedulesUpdate", + "summary": "Update schema refresh schedule", "tags": [ "Connections" ], @@ -32291,57 +33308,146 @@ "description": "Connection ID", "name": "connectionId", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "required": true, + "description": "Schedule ID", + "name": "scheduleId", + "in": "path" } ], "requestBody": { - "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DbtEnvironmentCreateBody" + "type": "object", + "properties": { + "hardRefresh": { + "type": "boolean", + "default": false, + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + } + }, + "required": [ + "schedule", + "timezone" + ], + "description": "Request body for updating a schema refresh schedule", + "title": "ConnectionsSchedulesUpdateBody" } } } }, "responses": { - "201": { - "description": "dbt environment created successfully", + "200": { + "description": "Schema refresh schedule updated successfully", "content": { "application/json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentItem" + "type": "object", + "properties": { + "connectionId": { + "type": "string", + "format": "uuid", + "description": "Connection ID this schedule belongs to", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - { - "description": "Created dbt environment", - "title": "DbtEnvironmentCreateResponse" + "createdAt": { + "type": "string", + "description": "Schedule creation timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" + }, + "description": { + "type": "string", + "description": "Human-readable schedule description", + "example": "Runs daily at 2:00 AM EST" + }, + "disabledAt": { + "type": [ + "string", + "null" + ], + "description": "Timestamp when schedule was disabled (ISO 8601)", + "example": null + }, + "hardRefresh": { + "type": "boolean", + "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", + "example": false + }, + "schedule": { + "type": "string", + "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", + "example": "0 2 * * ? *" + }, + "scheduleId": { + "type": "string", + "format": "uuid", + "description": "Unique schedule identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "timezone": { + "type": "string", + "description": "IANA timezone for schedule execution", + "example": "America/New_York" + }, + "updatedAt": { + "type": "string", + "description": "Schedule last update timestamp (ISO 8601)", + "example": "2024-01-15T10:30:00Z" } - ] + }, + "required": [ + "connectionId", + "createdAt", + "description", + "disabledAt", + "hardRefresh", + "schedule", + "scheduleId", + "timezone", + "updatedAt" + ], + "description": "Updated schedule response", + "title": "ConnectionsSchedulesUpdateResponse" } } } }, "400": { - "description": "Invalid request body" + "description": "Invalid cron expression or timezone" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied or connection does not support dbt" + "description": "Permission denied - connection admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection or schedule not found" } } - } - }, - "/api/v1/connections/{connectionId}/dbt/environments/{environmentId}": { - "put": { - "description": "Update an existing dbt environment for a connection.", - "operationId": "connectionsDbtEnvironmentsUpdate", - "summary": "Update dbt environment", + }, + "delete": { + "operationId": "connectionsSchedulesDelete", + "summary": "Delete schema refresh schedule", "tags": [ "Connections" ], @@ -32362,118 +33468,253 @@ "schema": { "type": "string", "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" + "description": "Schedule ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Environment ID", - "name": "environmentId", + "description": "Schedule ID", + "name": "scheduleId", "in": "path" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DbtEnvironmentUpdateBody" + "responses": { + "200": { + "description": "Schema refresh schedule deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true + } + }, + "required": [ + "success" + ], + "description": "Delete schedule response", + "title": "ConnectionsSchedulesDeleteResponse" + } } } + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Permission denied - connection admin role required" + }, + "404": { + "description": "Connection or schedule not found" } - }, + } + } + }, + "/api/v1/connection-environments": { + "get": { + "operationId": "connectionEnvironmentsList", + "summary": "List connection environments", + "tags": [ + "Connections" + ], "responses": { "200": { - "description": "dbt environment updated successfully", + "description": "List of connection environments", "content": { "application/json": { "schema": { - "allOf": [ - { - "$ref": "#/components/schemas/DbtEnvironmentItem" - }, - { - "description": "Updated dbt environment", - "title": "DbtEnvironmentUpdateResponse" + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" + }, + "description": "List of connection environments" } - ] + }, + "required": [ + "connectionEnvironments" + ], + "description": "List connection environments response", + "title": "ConnectionsEnvironmentsListResponse" } } } }, - "400": { - "description": "Invalid request body" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied or connection does not support dbt" - }, - "404": { - "description": "Connection or environment not found" + "description": "Permission denied - admin role required" } } }, - "delete": { - "description": "Delete a dbt environment from a connection.", - "operationId": "connectionsDbtEnvironmentsDelete", - "summary": "Delete dbt environment", + "post": { + "operationId": "connectionEnvironmentsCreate", + "summary": "Create connection environments", "tags": [ "Connections" ], - "parameters": [ - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Environment ID", - "example": "247dc6dc-2a58-4688-9521-c5ed3e99c1e8" - }, - "required": true, - "description": "Environment ID", - "name": "environmentId", - "in": "path" + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "environmentConnectionIds": { + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "IDs of connections to use as environments", + "example": [ + "550e8400-e29b-41d4-a716-446655440002", + "550e8400-e29b-41d4-a716-446655440003" + ] + } + }, + "required": [ + "baseConnectionId", + "environmentConnectionIds" + ], + "description": "Request body for creating connection environments", + "title": "ConnectionsEnvironmentsCreateBody" + } + } } - ], + }, "responses": { - "200": { - "description": "dbt environment deleted successfully", + "201": { + "description": "Connection environments created successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DbtEnvironmentDeleteResponse" + "type": "object", + "properties": { + "connectionEnvironments": { + "type": "array", + "items": { + "type": "object", + "properties": { + "baseConnectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the base connection", + "example": "550e8400-e29b-41d4-a716-446655440000" + }, + "connectionId": { + "type": "string", + "format": "uuid", + "description": "ID of the environment connection", + "example": "550e8400-e29b-41d4-a716-446655440002" + }, + "id": { + "type": "string", + "format": "uuid", + "description": "Unique connection environment identifier", + "example": "550e8400-e29b-41d4-a716-446655440001" + }, + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "baseConnectionId", + "connectionId", + "id", + "userAttributeValues" + ], + "description": "Connection environment object", + "title": "ConnectionEnvironment" + }, + "description": "Created connection environments" + } + }, + "required": [ + "connectionEnvironments" + ], + "description": "Create connection environments response", + "title": "ConnectionsEnvironmentsCreateResponse" } } } }, + "400": { + "description": "Invalid request body or connection IDs" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied or connection does not support dbt" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection or environment not found" + "description": "Base connection or environment connection not found" } } } }, - "/api/v1/connections/{connectionId}/schedules": { - "get": { - "operationId": "connectionsSchedulesList", - "summary": "List schema refresh schedules", + "/api/v1/connection-environments/{id}": { + "put": { + "operationId": "connectionEnvironmentsUpdate", + "summary": "Update connection environment", "tags": [ "Connections" ], @@ -32482,119 +33723,82 @@ "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Connection environment ID", + "name": "id", "in": "path" } ], - "responses": { - "200": { - "description": "List of schema refresh schedules", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "schedules": { - "type": "array", - "items": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Schema refresh schedule object", - "title": "ConnectionSchedule" - }, - "description": "List of schema refresh schedules" + "requestBody": { + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "userAttributeValues": { + "type": "array", + "items": { + "type": "string" + }, + "description": "User attribute values for this environment", + "example": [ + "us-east", + "production" + ] + } + }, + "required": [ + "userAttributeValues" + ], + "description": "Request body for updating a connection environment", + "title": "ConnectionsEnvironmentsUpdateBody" + } + } + } + }, + "responses": { + "200": { + "description": "Connection environment updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "success": { + "type": "boolean", + "description": "Whether the operation succeeded", + "example": true } }, "required": [ - "schedules" + "success" ], - "description": "List schedules response", - "title": "ConnectionsSchedulesListResponse" + "description": "Update connection environment response", + "title": "ConnectionsEnvironmentsUpdateResponse" } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection environment not found" } } }, - "post": { - "operationId": "connectionsSchedulesCreate", - "summary": "Create schema refresh schedule", + "delete": { + "operationId": "connectionEnvironmentsDelete", + "summary": "Delete connection environment", "tags": [ "Connections" ], @@ -32603,909 +33807,579 @@ "schema": { "type": "string", "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Connection environment ID", + "example": "550e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Connection environment ID", + "name": "id", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "hardRefresh": { - "type": "boolean", - "default": false, - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for creating a schema refresh schedule", - "title": "ConnectionsSchedulesCreateBody" - } - } - } - }, "responses": { - "201": { - "description": "Schema refresh schedule created successfully", + "200": { + "description": "Connection environment deleted successfully", "content": { "application/json": { "schema": { "type": "object", "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { + "success": { "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" + "description": "Whether the operation succeeded", + "example": true } }, "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" + "success" ], - "description": "Created schedule response", - "title": "ConnectionsSchedulesCreateResponse" + "description": "Delete connection environment response", + "title": "ConnectionsEnvironmentsDeleteResponse" } } } }, - "400": { - "description": "Invalid cron expression or timezone" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - admin role required" }, "404": { - "description": "Connection not found" + "description": "Connection environment not found" } } } }, - "/api/v1/connections/{connectionId}/schedules/{scheduleId}": { + "/api/v1/content": { "get": { - "operationId": "connectionsSchedulesGet", - "summary": "Get schema refresh schedule", + "operationId": "contentList", + "summary": "List content", "tags": [ - "Connections" + "Content" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by creator user ID" + }, + "required": false, + "description": "Filter by creator user ID", + "name": "creatorId", + "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter by folder ID (cannot be used with path)" + }, + "required": false, + "description": "Filter by folder ID (cannot be used with path)", + "name": "folderId", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of fields to include (e.g., _count,labels)" + }, + "required": false, + "description": "Comma-separated list of fields to include (e.g., _count,labels)", + "name": "include", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Filter by folder path (cannot be used with folderId)", + "example": "/reports/sales" + }, + "required": false, + "description": "Filter by folder path (cannot be used with folderId)", + "name": "path", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "organization", + "restricted" + ], + "description": "Filter by share scope", + "example": "organization" + }, + "required": false, + "description": "Filter by share scope", + "name": "scope", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "description": "Sort direction", + "example": "asc" }, - "required": true, - "description": "Connection ID", - "name": "connectionId", - "in": "path" + "required": false, + "description": "Sort direction", + "name": "sortDirection", + "in": "query" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "enum": [ + "name", + "favorites" + ], + "description": "Field to sort by", + "example": "name" }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" + "required": false, + "description": "Field to sort by", + "name": "sortField", + "in": "query" } ], "responses": { "200": { - "description": "Schema refresh schedule details", + "description": "List of content (documents and folders)", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Get schedule response", - "title": "ConnectionsSchedulesGetResponse" + "$ref": "#/components/schemas/ContentListResponse" } } } }, + "400": { + "description": "Invalid query parameters (cannot use both folderId and path)" + }, "401": { "description": "Authentication required" }, - "403": { - "description": "Permission denied - connection admin role required" - }, "404": { - "description": "Connection or schedule not found" + "description": "Folder not found (when filtering by path)" } } - }, - "put": { - "operationId": "connectionsSchedulesUpdate", - "summary": "Update schema refresh schedule", + } + }, + "/api/v1/dashboards/{identifier}/download": { + "post": { + "operationId": "dashboardsDownload", + "summary": "Initiate dashboard download", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Target user membership ID (for org-scoped API keys)" }, - "required": true, - "description": "Schedule ID", - "name": "scheduleId", - "in": "path" + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "hardRefresh": { - "type": "boolean", - "default": false, - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false (the default), it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - } - }, - "required": [ - "schedule", - "timezone" - ], - "description": "Request body for updating a schema refresh schedule", - "title": "ConnectionsSchedulesUpdateBody" + "$ref": "#/components/schemas/DashboardsDownloadBody" } } } }, "responses": { "200": { - "description": "Schema refresh schedule updated successfully", + "description": "Download job initiated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "connectionId": { - "type": "string", - "format": "uuid", - "description": "Connection ID this schedule belongs to", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "createdAt": { - "type": "string", - "description": "Schedule creation timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - }, - "description": { - "type": "string", - "description": "Human-readable schedule description", - "example": "Runs daily at 2:00 AM EST" - }, - "disabledAt": { - "type": [ - "string", - "null" - ], - "description": "Timestamp when schedule was disabled (ISO 8601)", - "example": null - }, - "hardRefresh": { - "type": "boolean", - "description": "When true, the scheduled refresh performs a hard refresh that fully discards and rebuilds the schema model. When false, it performs a soft refresh that merges newly generated views with the existing model.", - "example": false - }, - "schedule": { - "type": "string", - "description": "AWS EventBridge cron expression (6 fields: minute hour day-of-month month day-of-week year). See https://docs.aws.amazon.com/eventbridge/latest/userguide/eb-cron-expressions.html", - "example": "0 2 * * ? *" - }, - "scheduleId": { - "type": "string", - "format": "uuid", - "description": "Unique schedule identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "timezone": { - "type": "string", - "description": "IANA timezone for schedule execution", - "example": "America/New_York" - }, - "updatedAt": { - "type": "string", - "description": "Schedule last update timestamp (ISO 8601)", - "example": "2024-01-15T10:30:00Z" - } - }, - "required": [ - "connectionId", - "createdAt", - "description", - "disabledAt", - "hardRefresh", - "schedule", - "scheduleId", - "timezone", - "updatedAt" - ], - "description": "Updated schedule response", - "title": "ConnectionsSchedulesUpdateResponse" + "$ref": "#/components/schemas/DashboardsDownloadResponse" } } } }, "400": { - "description": "Invalid cron expression or timezone" + "description": "Invalid request body or filter configuration" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - connection admin role required" + "description": "Permission denied - cannot download this dashboard" }, "404": { - "description": "Connection or schedule not found" + "description": "Dashboard not found" + }, + "409": { + "description": "Download already in progress for this dashboard" + }, + "500": { + "description": "Failed to initiate download" } } - }, - "delete": { - "operationId": "connectionsSchedulesDelete", - "summary": "Delete schema refresh schedule", + } + }, + "/api/v1/dashboards/{identifier}/download/{jobId}": { + "get": { + "operationId": "dashboardsDownloadFile", + "summary": "Get download file", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection ID", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection ID", - "name": "connectionId", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Schedule ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" }, "required": true, - "description": "Schedule ID", - "name": "scheduleId", + "description": "Download job ID (UUID)", + "name": "jobId", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "responses": { "200": { - "description": "Schema refresh schedule deleted successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete schedule response", - "title": "ConnectionsSchedulesDeleteResponse" - } - } - } + "description": "File ready - binary content streamed" + }, + "202": { + "description": "Download job still in progress" }, "401": { "description": "Authentication required" }, - "403": { - "description": "Permission denied - connection admin role required" - }, "404": { - "description": "Connection or schedule not found" + "description": "Dashboard or download job not found" + }, + "410": { + "description": "Download job failed" + }, + "500": { + "description": "Failed to retrieve download artifact" } } } }, - "/api/v1/connection-environments": { + "/api/v1/dashboards/{identifier}/download/{jobId}/status": { "get": { - "operationId": "connectionEnvironmentsList", - "summary": "List connection environments", - "tags": [ - "Connections" - ], - "responses": { - "200": { - "description": "List of connection environments", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "List of connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "List connection environments response", - "title": "ConnectionsEnvironmentsListResponse" - } - } - } - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied - admin role required" - } - } - }, - "post": { - "operationId": "connectionEnvironmentsCreate", - "summary": "Create connection environments", + "operationId": "dashboardsDownloadStatus", + "summary": "Get download job status", "tags": [ - "Connections" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "environmentConnectionIds": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "IDs of connections to use as environments", - "example": [ - "550e8400-e29b-41d4-a716-446655440002", - "550e8400-e29b-41d4-a716-446655440003" - ] - } - }, - "required": [ - "baseConnectionId", - "environmentConnectionIds" - ], - "description": "Request body for creating connection environments", - "title": "ConnectionsEnvironmentsCreateBody" - } - } - } - }, - "responses": { - "201": { - "description": "Connection environments created successfully", - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "connectionEnvironments": { - "type": "array", - "items": { - "type": "object", - "properties": { - "baseConnectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the base connection", - "example": "550e8400-e29b-41d4-a716-446655440000" - }, - "connectionId": { - "type": "string", - "format": "uuid", - "description": "ID of the environment connection", - "example": "550e8400-e29b-41d4-a716-446655440002" - }, - "id": { - "type": "string", - "format": "uuid", - "description": "Unique connection environment identifier", - "example": "550e8400-e29b-41d4-a716-446655440001" - }, - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "baseConnectionId", - "connectionId", - "id", - "userAttributeValues" - ], - "description": "Connection environment object", - "title": "ConnectionEnvironment" - }, - "description": "Created connection environments" - } - }, - "required": [ - "connectionEnvironments" - ], - "description": "Create connection environments response", - "title": "ConnectionsEnvironmentsCreateResponse" - } - } - } + "Dashboards" + ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" + }, + "required": true, + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", + "in": "path" }, - "400": { - "description": "Invalid request body or connection IDs" + { + "schema": { + "type": "string", + "description": "Download job ID (UUID)", + "example": "123e4567-e89b-12d3-a456-426614174000" + }, + "required": true, + "description": "Download job ID (UUID)", + "name": "jobId", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "200": { + "description": "Download job status" }, "401": { "description": "Authentication required" }, - "403": { - "description": "Permission denied - admin role required" - }, "404": { - "description": "Base connection or environment connection not found" + "description": "Dashboard or download job not found" } } } }, - "/api/v1/connection-environments/{id}": { - "put": { - "operationId": "connectionEnvironmentsUpdate", - "summary": "Update connection environment", + "/api/v1/dashboards/{identifier}/filters": { + "get": { + "operationId": "dashboardsGetFilters", + "summary": "Get dashboard filters", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection environment ID", - "name": "id", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "type": "object", - "properties": { - "userAttributeValues": { - "type": "array", - "items": { - "type": "string" - }, - "description": "User attribute values for this environment", - "example": [ - "us-east", - "production" - ] - } - }, - "required": [ - "userAttributeValues" - ], - "description": "Request body for updating a connection environment", - "title": "ConnectionsEnvironmentsUpdateBody" - } - } - } - }, "responses": { "200": { - "description": "Connection environment updated successfully", + "description": "Dashboard filter and control configuration", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Update connection environment response", - "title": "ConnectionsEnvironmentsUpdateResponse" + "$ref": "#/components/schemas/DashboardFiltersResponse" } } } }, - "400": { - "description": "Invalid request body" - }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - VIEWER role required" }, "404": { - "description": "Connection environment not found" + "description": "Dashboard not found" } } }, - "delete": { - "operationId": "connectionEnvironmentsDelete", - "summary": "Delete connection environment", + "patch": { + "operationId": "dashboardsUpdateFilters", + "summary": "Update dashboard filters", "tags": [ - "Connections" + "Dashboards" ], "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Connection environment ID", - "example": "550e8400-e29b-41d4-a716-446655440001" + "description": "Dashboard identifier (short ID or UUID)", + "example": "12db1a0a" }, "required": true, - "description": "Connection environment ID", - "name": "id", + "description": "Dashboard identifier (short ID or UUID)", + "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" + } + } + } + }, "responses": { "200": { - "description": "Connection environment deleted successfully", + "description": "Filters updated successfully", "content": { "application/json": { "schema": { - "type": "object", - "properties": { - "success": { - "type": "boolean", - "description": "Whether the operation succeeded", - "example": true - } - }, - "required": [ - "success" - ], - "description": "Delete connection environment response", - "title": "ConnectionsEnvironmentsDeleteResponse" + "$ref": "#/components/schemas/DashboardFiltersResponse" } } } }, + "400": { + "description": "Invalid request body - must include at least one filter, control, or filterOrder" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - admin role required" + "description": "Permission denied - EDITOR role required" }, "404": { - "description": "Connection environment not found" + "description": "Dashboard not found or document does not have a dashboard" + }, + "409": { + "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." } } } }, - "/api/v1/content": { + "/api/v1/documents": { "get": { - "operationId": "contentList", - "summary": "List content", + "operationId": "documentsList", + "summary": "List documents", "tags": [ - "Content" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 + "format": "uuid", + "description": "Filter by creator membership ID" }, "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", + "description": "Filter by creator membership ID", + "name": "creatorId", "in": "query" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Filter by creator user ID" + "description": "Cursor for pagination" }, "required": false, - "description": "Filter by creator user ID", - "name": "creatorId", + "description": "Cursor for pagination", + "name": "cursor", "in": "query" }, { "schema": { "type": "string", "format": "uuid", - "description": "Filter by folder ID (cannot be used with path)" + "description": "Filter by folder ID" }, "required": false, - "description": "Filter by folder ID (cannot be used with path)", + "description": "Filter by folder ID", "name": "folderId", "in": "query" }, { "schema": { "type": "string", - "description": "Comma-separated list of fields to include (e.g., _count,labels)" + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", + "example": "_count,labels" }, "required": false, - "description": "Comma-separated list of fields to include (e.g., _count,labels)", + "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", "name": "include", "in": "query" }, { "schema": { "type": "string", - "description": "Filter by folder path (cannot be used with folderId)", - "example": "/reports/sales" + "description": "Comma-separated list of label names to filter by", + "example": "verified,important" }, "required": false, - "description": "Filter by folder path (cannot be used with folderId)", - "name": "path", + "description": "Comma-separated list of label names to filter by", + "name": "labels", "in": "query" }, { "schema": { - "type": "string", - "enum": [ - "organization", - "restricted" - ], - "description": "Filter by share scope", - "example": "organization" + "type": "integer", + "exclusiveMinimum": 0, + "default": 50, + "description": "Number of records per page" }, "required": false, - "description": "Filter by share scope", - "name": "scope", + "description": "Number of records per page", + "name": "pageSize", "in": "query" }, { @@ -33515,8 +34389,8 @@ "asc", "desc" ], - "description": "Sort direction", - "example": "asc" + "default": "asc", + "description": "Sort direction" }, "required": false, "description": "Sort direction", @@ -33528,269 +34402,318 @@ "type": "string", "enum": [ "name", - "favorites" + "favorites", + "updatedAt", + "visits" ], - "description": "Field to sort by", - "example": "name" + "default": "name", + "description": "Field to sort by" }, "required": false, "description": "Field to sort by", "name": "sortField", "in": "query" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Filter documents visible to this membership ID" + }, + "required": false, + "description": "Filter documents visible to this membership ID", + "name": "userId", + "in": "query" } ], "responses": { "200": { - "description": "List of content (documents and folders)", + "description": "Paginated list of documents", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/ContentListResponse" + "$ref": "#/components/schemas/DocumentsListResponse" + } + } + } + }, + "401": { + "description": "Authentication required" + } + } + }, + "post": { + "operationId": "documentsCreate", + "summary": "Create document", + "tags": [ + "Documents" + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateBody" + } + } + } + }, + "responses": { + "201": { + "description": "Document created successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsCreateResponse" } } } }, "400": { - "description": "Invalid query parameters (cannot use both folderId and path)" + "description": "Invalid request body" }, "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied" + }, "404": { - "description": "Folder not found (when filtering by path)" + "description": "Model or branch not found" } } } }, - "/api/v1/dashboards/{identifier}/download": { - "post": { - "operationId": "dashboardsDownload", - "summary": "Initiate dashboard download", + "/api/v1/documents/{identifier}": { + "get": { + "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", + "operationId": "documentsGet", + "summary": "Get document", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + } + ], + "responses": { + "200": { + "description": "Document details", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetResponse" + } + } + } }, + "400": { + "description": "Analysis documents are not supported" + }, + "401": { + "description": "Authentication required" + }, + "403": { + "description": "Insufficient permissions to view the document" + }, + "404": { + "description": "Document not found" + } + } + }, + "put": { + "deprecated": true, + "description": "**Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Removal scheduled per the `Sunset` response header.\n\nUpdates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", + "operationId": "documentsPut", + "summary": "Replace document (full replacement)", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsDownloadBody" + "$ref": "#/components/schemas/DocumentsPutBody" } } } }, "responses": { "200": { - "description": "Download job initiated successfully", + "description": "Document replaced successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsDownloadResponse" + "$ref": "#/components/schemas/DocumentsPutResponse" } } } }, "400": { - "description": "Invalid request body or filter configuration" + "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - cannot download this dashboard" + "description": "Insufficient permissions to update the document" }, "404": { - "description": "Dashboard not found" + "description": "Document not found" }, "409": { - "description": "Download already in progress for this dashboard" - }, - "500": { - "description": "Failed to initiate download" + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } - } - }, - "/api/v1/dashboards/{identifier}/download/{jobId}": { - "get": { - "operationId": "dashboardsDownloadFile", - "summary": "Get download file", + }, + "patch": { + "deprecated": true, + "description": "**Deprecated** — use `PATCH /api/v2/documents/{identifier}/draft` (and the related `/draft` routes). Removal scheduled per the `Sunset` response header.\n\nUpdates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", + "operationId": "documentsUpdate", + "summary": "Rename document", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateBody" + } + } + } + }, "responses": { "200": { - "description": "File ready - binary content streamed" + "description": "Document updated successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdateResponse" + } + } + } }, - "202": { - "description": "Download job still in progress" + "400": { + "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" }, "401": { "description": "Authentication required" }, - "404": { - "description": "Dashboard or download job not found" + "403": { + "description": "Permission denied - EDITOR role required" }, - "410": { - "description": "Download job failed" + "404": { + "description": "Document not found" }, - "500": { - "description": "Failed to retrieve download artifact" + "409": { + "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } - } - }, - "/api/v1/dashboards/{identifier}/download/{jobId}/status": { - "get": { - "operationId": "dashboardsDownloadStatus", - "summary": "Get download job status", - "tags": [ - "Dashboards" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" - }, - "required": true, - "description": "Dashboard identifier (short ID or UUID)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Download job ID (UUID)", - "example": "123e4567-e89b-12d3-a456-426614174000" - }, - "required": true, - "description": "Download job ID (UUID)", - "name": "jobId", - "in": "path" - }, + }, + "delete": { + "operationId": "documentsDelete", + "summary": "Delete document", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], "responses": { "200": { - "description": "Download job status" + "description": "Document deleted successfully", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SuccessResponse" + } + } + } }, "401": { "description": "Authentication required" }, + "403": { + "description": "Permission denied - MANAGER role required" + }, "404": { - "description": "Dashboard or download job not found" + "description": "Document not found" } } } }, - "/api/v1/dashboards/{identifier}/filters": { + "/api/v1/documents/{identifier}/queries": { "get": { - "operationId": "dashboardsGetFilters", - "summary": "Get dashboard filters", + "operationId": "documentsGetQueries", + "summary": "List document queries", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { "200": { - "description": "Dashboard filter and control configuration", + "description": "List of queries in the document", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" + "$ref": "#/components/schemas/DocumentsGetQueriesResponse" } } } @@ -33799,85 +34722,73 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - VIEWER role required" + "description": "Permission denied" }, "404": { - "description": "Dashboard not found" + "description": "Document not found" } } - }, - "patch": { - "operationId": "dashboardsUpdateFilters", - "summary": "Update dashboard filters", + } + }, + "/api/v1/documents/{identifier}/move": { + "put": { + "operationId": "documentsMove", + "summary": "Move document", "tags": [ - "Dashboards" + "Documents" ], "parameters": [ { "schema": { "type": "string", - "description": "Dashboard identifier (short ID or UUID)", - "example": "12db1a0a" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, "required": true, - "description": "Dashboard identifier (short ID or UUID)", + "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardsUpdateFiltersBody" + "$ref": "#/components/schemas/DocumentsMoveBody" } } } }, "responses": { "200": { - "description": "Filters updated successfully", + "description": "Document moved successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DashboardFiltersResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body - must include at least one filter, control, or filterOrder" + "description": "Invalid folder path or scope" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Dashboard not found or document does not have a dashboard" - }, - "409": { - "description": "Conflict - draft already exists. Set clearExistingDraft to true to proceed." + "description": "Document or folder not found" } } } }, - "/api/v1/documents": { + "/api/v1/documents/{identifier}/permissions": { "get": { - "operationId": "documentsList", - "summary": "List documents", + "operationId": "documentsGetPermissions", + "summary": "Get document permissions", "tags": [ "Documents" ], @@ -33885,175 +34796,157 @@ { "schema": { "type": "string", - "format": "uuid", - "description": "Filter by creator membership ID" - }, - "required": false, - "description": "Filter by creator membership ID", - "name": "creatorId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Cursor for pagination", - "name": "cursor", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" }, { "schema": { "type": "string", "format": "uuid", - "description": "Filter by folder ID" - }, - "required": false, - "description": "Filter by folder ID", - "name": "folderId", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "example": "_count,labels" - }, - "required": false, - "description": "Comma-separated list of additional fields to include: _count, labels, includeDeleted, onlyFavorites, onlySharedWithMe. onlySharedWithMe requires userId or user-scoped key and cannot be combined with onlyFavorites or folderId.", - "name": "include", - "in": "query" - }, - { - "schema": { - "type": "string", - "description": "Comma-separated list of label names to filter by", - "example": "verified,important" - }, - "required": false, - "description": "Comma-separated list of label names to filter by", - "name": "labels", - "in": "query" - }, - { - "schema": { - "type": "integer", - "exclusiveMinimum": 0, - "default": 50, - "description": "Number of records per page" + "description": "User membership ID to check permissions for" }, - "required": false, - "description": "Number of records per page", - "name": "pageSize", + "required": true, + "description": "User membership ID to check permissions for", + "name": "userId", "in": "query" + } + ], + "responses": { + "200": { + "description": "User permissions for the document", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" + } + } + } }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction" - }, - "required": false, - "description": "Sort direction", - "name": "sortDirection", - "in": "query" + "401": { + "description": "Authentication required" }, - { - "schema": { - "type": "string", - "enum": [ - "name", - "favorites", - "updatedAt", - "visits" - ], - "default": "name", - "description": "Field to sort by" - }, - "required": false, - "description": "Field to sort by", - "name": "sortField", - "in": "query" + "403": { + "description": "Permission denied" }, + "404": { + "description": "Document or user not found" + } + } + }, + "put": { + "operationId": "documentsUpdatePermissionSettings", + "summary": "Update document permission settings", + "tags": [ + "Documents" + ], + "parameters": [ { "schema": { "type": "string", - "format": "uuid", - "description": "Filter documents visible to this membership ID" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" }, - "required": false, - "description": "Filter documents visible to this membership ID", - "name": "userId", - "in": "query" + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" + } + } + } + }, "responses": { "200": { - "description": "Paginated list of documents", + "description": "Permission settings updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsListResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, + "400": { + "description": "Invalid request body" + }, "401": { "description": "Authentication required" + }, + "403": { + "description": "Permission denied - MANAGER role required" + }, + "404": { + "description": "Document not found" } } }, "post": { - "operationId": "documentsCreate", - "summary": "Create document", + "operationId": "documentsAddPermits", + "summary": "Add document permits", "tags": [ "Documents" ], + "parameters": [ + { + "schema": { + "type": "string", + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + } + ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateBody" + "$ref": "#/components/schemas/DocumentsAddPermitsBody" } } } }, "responses": { - "201": { - "description": "Document created successfully", + "200": { + "description": "Permissions added successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body" + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied" + "description": "Permission denied - MANAGER role required" }, "404": { - "description": "Model or branch not found" + "description": "Document not found" } } - } - }, - "/api/v1/documents/{identifier}": { - "get": { - "description": "Retrieves a document's configuration in a format compatible with PUT for round-trip editing. GET a document, modify the response, and PUT it back to update. Only dashboard documents are supported; analysis documents return 400.", - "operationId": "documentsGet", - "summary": "Get document", + }, + "patch": { + "operationId": "documentsUpdatePermits", + "summary": "Update document permits", "tags": [ "Documents" ], @@ -34070,35 +34963,43 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" + } + } + } + }, "responses": { "200": { - "description": "Document details", + "description": "Permissions updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsGetResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Analysis documents are not supported" + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions to view the document" + "description": "Permission denied - MANAGER role required" }, "404": { "description": "Document not found" } } }, - "put": { - "description": "Updates a document with the specified identifier. This endpoint performs a full resource replacement — all required fields must be provided and existing query presentations are replaced entirely. Only dashboard documents are supported; analysis documents and documents without an associated dashboard return 400. For published documents, the update goes through a draft/publish workflow automatically; if a draft already exists, the request returns 409 unless `clearExistingDraft` is set to `true`.", - "operationId": "documentsPut", - "summary": "Replace document (full replacement)", + "delete": { + "operationId": "documentsRevokePermits", + "summary": "Revoke document permits", "tags": [ "Documents" ], @@ -34119,43 +35020,41 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsPutBody" + "$ref": "#/components/schemas/DocumentsRevokePermitsBody" } } } }, "responses": { "200": { - "description": "Document replaced successfully", + "description": "Permissions revoked successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsPutResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Invalid request body, missing required fields, or validation error (also returned for analysis documents and documents without an associated dashboard)" + "description": "Invalid request body - userIds or userGroupIds required" }, "401": { "description": "Authentication required" }, "403": { - "description": "Insufficient permissions to update the document" + "description": "Permission denied - MANAGER role required" }, "404": { "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" } } - }, - "patch": { - "description": "Updates a document's name, description, and/or identifier. This is a partial update — only provided fields are modified, and at least one of `name`, `description`, or `identifier` must be supplied. When `identifier` is changed, the previous identifier is retained in the document identifier history and continues to redirect. For published documents, the update goes through a draft/publish workflow automatically.", - "operationId": "documentsUpdate", - "summary": "Rename document", + } + }, + "/api/v1/documents/{identifier}/draft": { + "post": { + "operationId": "documentsCreateDraft", + "summary": "Create document draft", "tags": [ "Documents" ], @@ -34176,24 +35075,24 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsUpdateBody" + "$ref": "#/components/schemas/DocumentsCreateDraftBody" } } } }, "responses": { "200": { - "description": "Document updated successfully", + "description": "Draft created or existing draft returned", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsUpdateResponse" + "$ref": "#/components/schemas/DocumentsCreateDraftResponse" } } } }, "400": { - "description": "Invalid request body or validation error (e.g. missing name/description/identifier, name too long, identifier already in use)" + "description": "Document is not eligible for publishing workflow" }, "401": { "description": "Authentication required" @@ -34202,16 +35101,13 @@ "description": "Permission denied - EDITOR role required" }, "404": { - "description": "Document not found" - }, - "409": { - "description": "Draft already exists - set clearExistingDraft to true to discard it and proceed" + "description": "Document or branch not found" } } }, "delete": { - "operationId": "documentsDelete", - "summary": "Delete document", + "operationId": "documentsDiscardDraft", + "summary": "Discard document draft", "tags": [ "Documents" ], @@ -34228,13 +35124,22 @@ "in": "path" } ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsDiscardDraftBody" + } + } + } + }, "responses": { "200": { - "description": "Document deleted successfully", + "description": "Draft discarded successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" } } } @@ -34243,18 +35148,19 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { - "description": "Document not found" + "description": "Document or draft not found" } } } }, - "/api/v1/documents/{identifier}/queries": { + "/api/v1/documents/{identifier}/drafts": { "get": { - "operationId": "documentsGetQueries", - "summary": "List document queries", + "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", + "operationId": "documentsListDrafts", + "summary": "List document drafts", "tags": [ "Documents" ], @@ -34269,24 +35175,38 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "example": "archived" + }, + "required": false, + "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", + "name": "include", + "in": "query" } ], "responses": { "200": { - "description": "List of queries in the document", + "description": "List of drafts for the document", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsGetQueriesResponse" + "$ref": "#/components/schemas/DocumentsListDraftsResponse" } } } }, + "400": { + "description": "Invalid query parameters" + }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to view the document" }, "404": { "description": "Document not found" @@ -34294,10 +35214,10 @@ } } }, - "/api/v1/documents/{identifier}/move": { - "put": { - "operationId": "documentsMove", - "summary": "Move document", + "/api/v1/documents/{identifier}/duplicate": { + "post": { + "operationId": "documentsDuplicate", + "summary": "Duplicate document", "tags": [ "Documents" ], @@ -34312,36 +35232,47 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsMoveBody" + "$ref": "#/components/schemas/DocumentsDuplicateBody" } } } }, "responses": { - "200": { - "description": "Document moved successfully", + "201": { + "description": "Document duplicated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsDuplicateResponse" } } } }, "400": { - "description": "Invalid folder path or scope" + "description": "Invalid name or folder path" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document or folder not found" @@ -34349,10 +35280,10 @@ } } }, - "/api/v1/documents/{identifier}/permissions": { - "get": { - "operationId": "documentsGetPermissions", - "summary": "Get document permissions", + "/api/v1/documents/{identifier}/favorite": { + "put": { + "operationId": "documentsAddFavorite", + "summary": "Add document to favorites", "tags": [ "Documents" ], @@ -34372,24 +35303,17 @@ "schema": { "type": "string", "format": "uuid", - "description": "User membership ID to check permissions for" + "description": "Target user membership ID (for org-scoped API keys)" }, - "required": true, - "description": "User membership ID to check permissions for", + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", "name": "userId", "in": "query" } ], "responses": { - "200": { - "description": "User permissions for the document", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsGetPermissionsResponse" - } - } - } + "204": { + "description": "Favorite added successfully" }, "401": { "description": "Authentication required" @@ -34398,13 +35322,13 @@ "description": "Permission denied" }, "404": { - "description": "Document or user not found" + "description": "Document not found" } } }, - "put": { - "operationId": "documentsUpdatePermissionSettings", - "summary": "Update document permission settings", + "delete": { + "operationId": "documentsRemoveFavorite", + "summary": "Remove document from favorites", "tags": [ "Documents" ], @@ -34419,45 +35343,39 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" - } - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermissionSettingsBody" - } - } - } - }, - "responses": { - "200": { - "description": "Permission settings updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } }, - "400": { - "description": "Invalid request body" + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" + } + ], + "responses": { + "204": { + "description": "Favorite removed successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document not found" } } - }, - "post": { - "operationId": "documentsAddPermits", - "summary": "Add document permits", + } + }, + "/api/v1/documents/{identifier}/labels": { + "patch": { + "operationId": "documentsBulkUpdateLabels", + "summary": "Bulk update document labels", "tags": [ "Documents" ], @@ -34472,45 +35390,58 @@ "description": "Document identifier (either document ID or identifier slug)", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsAddPermitsBody" + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" } } } }, "responses": { "200": { - "description": "Permissions added successfully", + "description": "Labels updated successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" } } } }, "400": { - "description": "Invalid request body - userIds or userGroupIds required" + "description": "Invalid request - at least one label must be specified" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document not found" } } - }, - "patch": { - "operationId": "documentsUpdatePermits", - "summary": "Update document permits", + } + }, + "/api/v1/documents/{identifier}/labels/{labelName}": { + "put": { + "operationId": "documentsAddLabel", + "summary": "Add label to document", "tags": [ "Documents" ], @@ -34518,52 +35449,55 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsUpdatePermitsBody" - } - } - } - }, "responses": { - "200": { - "description": "Permissions updated successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" + "204": { + "description": "Label added successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { - "description": "Document not found" + "description": "Document or label not found" } } }, "delete": { - "operationId": "documentsRevokePermits", - "summary": "Revoke document permits", + "operationId": "documentsRemoveLabel", + "summary": "Remove label from document", "tags": [ "Documents" ], @@ -34571,43 +35505,46 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier", "name": "identifier", "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Label name", + "example": "verified" + }, + "required": true, + "description": "Label name", + "name": "labelName", + "in": "path" + }, + { + "schema": { + "type": "string", + "format": "uuid", + "description": "Target user membership ID (for org-scoped API keys)" + }, + "required": false, + "description": "Target user membership ID (for org-scoped API keys)", + "name": "userId", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsRevokePermitsBody" - } - } - } - }, "responses": { - "200": { - "description": "Permissions revoked successfully", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/SuccessResponse" - } - } - } - }, - "400": { - "description": "Invalid request body - userIds or userGroupIds required" + "204": { + "description": "Label removed successfully" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - MANAGER role required" + "description": "Permission denied" }, "404": { "description": "Document not found" @@ -34615,10 +35552,10 @@ } } }, - "/api/v1/documents/{identifier}/draft": { - "post": { - "operationId": "documentsCreateDraft", - "summary": "Create document draft", + "/api/v1/documents/{identifier}/transfer-ownership": { + "put": { + "operationId": "documentsTransferOwnership", + "summary": "Transfer document ownership", "tags": [ "Documents" ], @@ -34639,39 +35576,41 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftBody" + "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" } } } }, "responses": { "200": { - "description": "Draft created or existing draft returned", + "description": "Ownership transferred successfully", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsCreateDraftResponse" + "$ref": "#/components/schemas/SuccessResponse" } } } }, "400": { - "description": "Document is not eligible for publishing workflow" + "description": "Invalid user ID" }, "401": { "description": "Authentication required" }, "403": { - "description": "Permission denied - EDITOR role required" + "description": "Permission denied - MANAGER role or owner required" }, "404": { - "description": "Document or branch not found" + "description": "Document or user not found" } } - }, - "delete": { - "operationId": "documentsDiscardDraft", - "summary": "Discard document draft", + } + }, + "/api/v1/documents/{identifier}/access-list": { + "get": { + "operationId": "documentsAccessList", + "summary": "List document access principals", "tags": [ "Documents" ], @@ -34679,31 +35618,101 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" + "description": "Document identifier (either document ID or identifier slug)", + "example": "abc123" + }, + "required": true, + "description": "Document identifier (either document ID or identifier slug)", + "name": "identifier", + "in": "path" + }, + { + "schema": { + "type": "string", + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" + }, + "required": false, + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction (default: asc)", + "example": "desc" + }, + "required": false, + "description": "Sort direction (default: asc)", + "name": "sortDirection", + "in": "query" + }, + { + "schema": { + "type": "string", + "description": "Field to sort results by" + }, + "required": false, + "description": "Field to sort results by", + "name": "sortField", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "direct", + "folder" + ], + "description": "Filter by access source: direct or folder" + }, + "required": false, + "description": "Filter by access source: direct or folder", + "name": "accessSource", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "user", + "userGroup" + ], + "description": "Filter by principal type: user or userGroup" }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" + "required": false, + "description": "Filter by principal type: user or userGroup", + "name": "type", + "in": "query" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftBody" - } - } - } - }, "responses": { "200": { - "description": "Draft discarded successfully", + "description": "List of users and groups with access", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDiscardDraftResponse" + "$ref": "#/components/schemas/DocumentsAccessListResponse" } } } @@ -34712,19 +35721,19 @@ "description": "Authentication required" }, "403": { - "description": "Permission denied" + "description": "Permission denied - VIEWER role required" }, "404": { - "description": "Document or draft not found" + "description": "Document not found" } } } }, - "/api/v1/documents/{identifier}/drafts": { + "/api/v1/documents/{identifier}/favorites": { "get": { - "description": "Lists drafts for a document with branch context. By default only active drafts are returned; pass `include=archived` to also include soft-deleted drafts (retained ~7 days). Results are sorted by `createdAt` descending.", - "operationId": "documentsListDrafts", - "summary": "List document drafts", + "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", + "operationId": "documentsListFavorites", + "summary": "List users who favorited the document", "tags": [ "Documents" ], @@ -34743,22 +35752,52 @@ { "schema": { "type": "string", - "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", - "example": "archived" + "description": "Cursor for pagination (from previous response nextCursor)", + "example": "eyJpZCI6IjEyMzQ1In0" }, "required": false, - "description": "Comma-separated list of additional drafts to include. Only \"archived\" is recognized — when present, soft-deleted drafts (retained ~7 days) are returned alongside active drafts.", - "name": "include", + "description": "Cursor for pagination (from previous response nextCursor)", + "name": "cursor", + "in": "query" + }, + { + "schema": { + "type": "integer", + "minimum": 1, + "maximum": 100, + "default": 20, + "description": "Number of results per page (1-100, integer)", + "example": 20 + }, + "required": false, + "description": "Number of results per page (1-100, integer)", + "name": "pageSize", + "in": "query" + }, + { + "schema": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "default": "asc", + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "example": "desc" + }, + "required": false, + "description": "Sort direction by favoritedAt (default: asc — oldest first)", + "name": "sortDirection", "in": "query" } ], "responses": { "200": { - "description": "List of drafts for the document", + "description": "Paginated list of users who favorited the document", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsListDraftsResponse" + "$ref": "#/components/schemas/DocumentsListFavoritesResponse" } } } @@ -34770,7 +35809,7 @@ "description": "Authentication required" }, "403": { - "description": "Insufficient permissions to view the document" + "description": "Permission denied — caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" }, "404": { "description": "Document not found" @@ -34778,76 +35817,58 @@ } } }, - "/api/v1/documents/{identifier}/duplicate": { + "/api/v2/documents": { "post": { - "operationId": "documentsDuplicate", - "summary": "Duplicate document", + "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nWhen `containers` is omitted, every dashboard-eligible tile is auto-placed in a default layout. When `containers` is present, it fully defines the layout — tiles it does not reference are stored but not rendered.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to existing content).", + "operationId": "documentsV2Create", + "summary": "Create document", "tags": [ "Documents" ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateBody" + "$ref": "#/components/schemas/DocumentsV2CreateBody" } } } }, "responses": { "201": { - "description": "Document duplicated successfully", + "description": "Document created and published successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsDuplicateResponse" + "$ref": "#/components/schemas/DocumentsV2CreateResponse" } } } }, "400": { - "description": "Invalid name or folder path" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to create a document on this model." }, "404": { - "description": "Document or folder not found" + "description": "Base model or branch not found." + }, + "405": { + "description": "Method not allowed." } } } }, - "/api/v1/documents/{identifier}/favorite": { - "put": { - "operationId": "documentsAddFavorite", - "summary": "Add document to favorites", + "/api/v2/documents/{identifier}": { + "get": { + "description": "Read the document's current draft state (or the published state if no draft exists). Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2Get", + "summary": "Read document state", "tags": [ "Documents" ], @@ -34855,91 +35876,46 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { - "204": { - "description": "Favorite added successfully" + "200": { + "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2ReadResponse" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to read the document." }, "404": { - "description": "Document not found" - } - } - }, - "delete": { - "operationId": "documentsRemoveFavorite", - "summary": "Remove document from favorites", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Favorite removed successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" + "description": "Document not found." }, - "404": { - "description": "Document not found" + "422": { + "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." } } } }, - "/api/v1/documents/{identifier}/labels": { + "/api/v2/documents/{identifier}/draft": { "patch": { - "operationId": "documentsBulkUpdateLabels", - "summary": "Bulk update document labels", + "description": "Create a new draft on the published document and apply the patch. No auto-publish — the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", + "operationId": "documentsV2PatchDraft", + "summary": "Create draft and patch document", "tags": [ "Documents" ], @@ -34947,65 +35923,64 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "requestBody": { "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsBody" + "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" } } } }, "responses": { "200": { - "description": "Labels updated successfully", + "description": "Draft created and patch applied successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsBulkUpdateLabelsResponse" + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" } } } }, "400": { - "description": "Invalid request - at least one label must be specified" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to update the document." }, "404": { - "description": "Document not found" + "description": "Document or branch not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." } } } }, - "/api/v1/documents/{identifier}/labels/{labelName}": { - "put": { - "operationId": "documentsAddLabel", - "summary": "Add label to document", + "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { + "get": { + "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", + "operationId": "documentsV2GetDraft", + "summary": "Read draft state", "tags": [ "Documents" ], @@ -35013,55 +35988,55 @@ { "schema": { "type": "string", - "description": "Document identifier", - "example": "abc123" + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" }, "required": true, - "description": "Document identifier", - "name": "identifier", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", "in": "path" }, { "schema": { "type": "string", - "description": "Label name", - "example": "verified" + "description": "Published document identifier.", + "example": "abc123" }, "required": true, - "description": "Label name", - "name": "labelName", + "description": "Published document identifier.", + "name": "identifier", "in": "path" - }, - { - "schema": { - "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" } ], "responses": { - "204": { - "description": "Label added successfully" + "200": { + "description": "Draft state.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2ReadResponse" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied" + "description": "Insufficient permissions to read the draft." }, "404": { - "description": "Document or label not found" + "description": "Document or draft not found." + }, + "422": { + "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." } } }, - "delete": { - "operationId": "documentsRemoveLabel", - "summary": "Remove label from document", + "patch": { + "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, no publish.", + "operationId": "documentsV2PatchDraftByIdentifier", + "summary": "Patch draft", "tags": [ "Documents" ], @@ -35069,69 +36044,22 @@ { "schema": { "type": "string", - "description": "Document identifier", - "example": "abc123" - }, - "required": true, - "description": "Document identifier", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Label name", - "example": "verified" + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "example": "def456" }, "required": true, - "description": "Label name", - "name": "labelName", + "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", + "name": "draftIdentifier", "in": "path" }, { "schema": { "type": "string", - "format": "uuid", - "description": "Target user membership ID (for org-scoped API keys)" - }, - "required": false, - "description": "Target user membership ID (for org-scoped API keys)", - "name": "userId", - "in": "query" - } - ], - "responses": { - "204": { - "description": "Label removed successfully" - }, - "401": { - "description": "Authentication required" - }, - "403": { - "description": "Permission denied" - }, - "404": { - "description": "Document not found" - } - } - } - }, - "/api/v1/documents/{identifier}/transfer-ownership": { - "put": { - "operationId": "documentsTransferOwnership", - "summary": "Transfer document ownership", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Published document identifier.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Published document identifier.", "name": "identifier", "in": "path" } @@ -35140,41 +36068,51 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsTransferOwnershipBody" + "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" } } } }, "responses": { "200": { - "description": "Ownership transferred successfully", + "description": "Patch applied to draft successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/SuccessResponse" + "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" } } } }, "400": { - "description": "Invalid user ID" + "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." }, "401": { - "description": "Authentication required" + "description": "Authentication required." }, "403": { - "description": "Permission denied - MANAGER role or owner required" + "description": "Insufficient permissions to update the draft." }, "404": { - "description": "Document or user not found" + "description": "Document or draft not found." + }, + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + }, + "422": { + "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." } } } }, - "/api/v1/documents/{identifier}/access-list": { - "get": { - "operationId": "documentsAccessList", - "summary": "List document access principals", + "/api/v2/documents/{identifier}/draft/publish": { + "post": { + "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body — the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", + "operationId": "documentsV2PublishDraft", + "summary": "Publish draft", "tags": [ "Documents" ], @@ -35182,593 +36120,574 @@ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "example": "abc123" }, "required": true, - "description": "Document identifier (either document ID or identifier slug)", + "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", "name": "identifier", "in": "path" + } + ], + "responses": { + "200": { + "description": "Draft published successfully.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" + } + } + } }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 - }, - "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", - "in": "query" + "400": { + "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." }, - { - "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction (default: asc)", - "example": "desc" - }, - "required": false, - "description": "Sort direction (default: asc)", - "name": "sortDirection", - "in": "query" + "401": { + "description": "Authentication required." }, - { - "schema": { - "type": "string", - "description": "Field to sort results by" - }, - "required": false, - "description": "Field to sort results by", - "name": "sortField", - "in": "query" + "403": { + "description": "Insufficient permissions to publish the draft." }, - { - "schema": { - "type": "string", - "enum": [ - "direct", - "folder" - ], - "description": "Filter by access source: direct or folder" - }, - "required": false, - "description": "Filter by access source: direct or folder", - "name": "accessSource", - "in": "query" + "404": { + "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." }, - { - "schema": { - "type": "string", - "enum": [ - "user", - "userGroup" - ], - "description": "Filter by principal type: user or userGroup" - }, - "required": false, - "description": "Filter by principal type: user or userGroup", - "name": "type", - "in": "query" + "405": { + "description": "Method not allowed." + }, + "409": { + "description": "The target is not a published document." } + } + } + }, + "/api/v1/embed/sso/generate-session": { + "post": { + "operationId": "embedSsoGenerateSession", + "summary": "Generate embedded SSO session", + "tags": [ + "Embed" ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" + } + } + } + }, "responses": { "200": { - "description": "List of users and groups with access", + "description": "Session token generated", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsAccessListResponse" + "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" } } } }, + "400": { + "description": "Invalid request body" + }, "401": { - "description": "Authentication required" + "description": "Authentication required (API key with embed scope)" }, "403": { - "description": "Permission denied - VIEWER role required" - }, - "404": { - "description": "Document not found" + "description": "Permission denied - embed not enabled" } } } }, - "/api/v1/documents/{identifier}/favorites": { + "/api/v1/ai/eval/prompt-sets": { "get": { - "description": "Lists users who have favorited the document, paginated and sorted by favoritedAt. Document-centric counterpart to GET /api/v1/documents?include=onlyFavorites: useful for migration scripts that need to preserve favorites when replacing documents, without iterating every user in the organization.", - "operationId": "documentsListFavorites", - "summary": "List users who favorited the document", + "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", + "operationId": "aiEvalPromptSetsList", + "summary": "List eval prompt sets", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier (either document ID or identifier slug)", - "example": "abc123" - }, - "required": true, - "description": "Document identifier (either document ID or identifier slug)", - "name": "identifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Cursor for pagination (from previous response nextCursor)", - "example": "eyJpZCI6IjEyMzQ1In0" - }, - "required": false, - "description": "Cursor for pagination (from previous response nextCursor)", - "name": "cursor", - "in": "query" - }, - { - "schema": { - "type": "integer", - "minimum": 1, - "maximum": 100, - "default": 20, - "description": "Number of results per page (1-100, integer)", - "example": 20 + "enum": [ + "true", + "false" + ], + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "example": "false" }, "required": false, - "description": "Number of results per page (1-100, integer)", - "name": "pageSize", + "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "name": "archived", "in": "query" }, { "schema": { - "type": "string", - "enum": [ - "asc", - "desc" - ], - "default": "asc", - "description": "Sort direction by favoritedAt (default: asc — oldest first)", - "example": "desc" + "type": "array", + "items": { + "type": "string", + "format": "uuid" + }, + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." }, "required": false, - "description": "Sort direction by favoritedAt (default: asc — oldest first)", - "name": "sortDirection", + "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", + "name": "model_ids", "in": "query" } ], "responses": { "200": { - "description": "Paginated list of users who favorited the document", + "description": "List of prompt sets, sorted alphabetically by name.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsListFavoritesResponse" + "$ref": "#/components/schemas/EvalPromptSetsListResponse" } } } }, "400": { - "description": "Invalid query parameters" + "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required" + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Permission denied — caller lacks MANAGER on the document, or used a user-scoped (personal access token) API key (org-scoped only)" + "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document not found" + "description": "No eval-accessible models for this caller.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } } } - } - }, - "/api/v2/documents": { + }, "post": { - "description": "Create a brand-new document and publish it live. Accepts creation metadata (`modelId`, `name`, optional `identifier` / `description` / `folderId`) plus the same content slice as the PATCH body — `queryPresentations`, `controls`, `settings`, `containers`. The server mints internal tile identifiers, so callers omit `miniUuid`. Tiles in `queryPresentations` are merged by key over the single empty seed tile at key `\"1\"`; write to `\"1\"` (or send it as `null`) to replace the seed.\n\nThe new document is published live before the response returns. As a first publish of brand-new content it is not subject to the org’s `requirePullRequestToPublish` policy (which gates edits to existing content).", - "operationId": "documentsV2Create", - "summary": "Create document", + "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", + "operationId": "aiEvalPromptSetsCreate", + "summary": "Create an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "requestBody": { "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateBody" + "$ref": "#/components/schemas/EvalPromptSetsCreateBody" } } } }, "responses": { "201": { - "description": "Document created and published successfully.", + "description": "Prompt set created successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateResponse" + "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" } } } }, "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded), or the `identifier` is already in use." + "description": "Invalid request body.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required." + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Insufficient permissions to create a document on this model." - }, - "404": { - "description": "Base model or branch not found." - }, - "405": { - "description": "Method not allowed." + "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } } } } }, - "/api/v2/documents/{identifier}": { + "/api/v1/ai/eval/prompt-sets/{promptSetId}": { "get": { - "description": "Read the document's current draft state (or the published state if no draft exists). Returns the full `DocumentsV2ReadResponse` shape.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", - "operationId": "documentsV2Get", - "summary": "Read document state", + "description": "Get a single prompt set with all of its prompts.", + "operationId": "aiEvalPromptSetsGet", + "summary": "Get an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], "responses": { "200": { - "description": "Document state. A workbook-only document (no dashboard layout yet) returns only the workbook-scoped fields (`name`, `description`, `queryPresentations`); the dashboard-scoped `containers`, `controls`, and `settings` are omitted until a layout exists.", + "description": "Prompt set details.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalPromptSetsGetResponse" + } + } + } + }, + "400": { + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } + }, + "401": { + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } + }, + "403": { + "description": "Insufficient permissions.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2ReadResponse" + "$ref": "#/components/schemas/EvalApiError403" } } } }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to read the document." - }, "404": { - "description": "Document not found." - }, - "422": { - "description": "The document cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } } } - } - }, - "/api/v2/documents/{identifier}/draft": { + }, "patch": { - "description": "Create a new draft on the published document and apply the patch. No auto-publish — the response includes the new `draftIdentifier` for follow-up calls.\n\nPass an optional `branchId` to attach the draft to a branch; omit it for a draft on the main (unpublished) workspace.", - "operationId": "documentsV2PatchDraft", - "summary": "Create draft and patch document", + "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list — existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", + "operationId": "aiEvalPromptSetsUpdate", + "summary": "Update an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], "requestBody": { + "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2CreateDraftBody" + "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" } } } }, "responses": { "200": { - "description": "Draft created and patch applied successfully.", + "description": "Prompt set updated successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" } } } }, "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." - }, - "401": { - "description": "Authentication required." - }, - "403": { - "description": "Insufficient permissions to update the document." - }, - "404": { - "description": "Document or branch not found." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." - }, - "422": { - "description": "The document cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only document patched without a `containers` payload (or with an empty one)." - } - } - } - }, - "/api/v2/documents/{identifier}/draft/{draftIdentifier}": { - "get": { - "description": "Read the named draft's state. Returns the full `DocumentsV2ReadResponse` shape — same as the live-state read endpoint.\n\nThe response is structured so a caller can take it verbatim and submit it as the body of the draft PATCH routes. Tiles in `queryPresentations.data` are keyed by a stable record key (e.g. `\"1\"`, `\"2\"`) — the server uses that key to identify existing tiles for updates, so callers do not need to track or send any other identifier. Control IDs and container `instanceKey` / `referenceKey` values also round-trip unchanged.", - "operationId": "documentsV2GetDraft", - "summary": "Read draft state", - "tags": [ - "Documents" - ], - "parameters": [ - { - "schema": { - "type": "string", - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "example": "def456" - }, - "required": true, - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "name": "draftIdentifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Published document identifier.", - "example": "abc123" - }, - "required": true, - "description": "Published document identifier.", - "name": "identifier", - "in": "path" - } - ], - "responses": { - "200": { - "description": "Draft state.", + "description": "Invalid request body.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2ReadResponse" + "$ref": "#/components/schemas/EvalApiError400" } } } }, "401": { - "description": "Authentication required." + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Insufficient permissions to read the draft." + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document or draft not found." + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } }, "422": { - "description": "The draft cannot be read as a dashboard: a classic-layout dashboard (upgrade to the advanced layout first) or an app document." + "description": "A `prompts[].id` in the request does not belong to this prompt set.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } } } }, - "patch": { - "description": "Apply the patch to an existing draft addressed by `draftIdentifier`. Pure apply — no draft creation, no publish.", - "operationId": "documentsV2PatchDraftByIdentifier", - "summary": "Patch draft", + "delete": { + "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent — retrying drains any remaining runs.", + "operationId": "aiEvalPromptSetsArchive", + "summary": "Archive an eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "example": "def456" - }, - "required": true, - "description": "Draft workbook identifier (see `POST /api/v1/documents/{identifier}/draft`).", - "name": "draftIdentifier", - "in": "path" - }, - { - "schema": { - "type": "string", - "description": "Published document identifier.", - "example": "abc123" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Published document identifier.", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftBody" - } - } - } - }, "responses": { "200": { - "description": "Patch applied to draft successfully.", + "description": "Prompt set archived successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2PatchDraftResponse" + "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" } } } }, "400": { - "description": "Invalid request body or schema validation error (e.g. unknown top-level field, name too long, query presentation cap exceeded)." + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required." + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Insufficient permissions to update the draft." + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } + } + } }, "404": { - "description": "Document or draft not found." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document (drafts only attach to published documents), or a concurrent request just created the layout for this document — retry." + "description": "Prompt set not found.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } }, - "422": { - "description": "The draft cannot satisfy the patch: a classic-layout dashboard (upgrade to the advanced layout first), an app document, or a workbook-only draft patched without a `containers` payload (or with an empty one)." + "500": { + "description": "Archive committed but a run-cancellation failed; the set is already archived — safe to retry.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } } } } }, - "/api/v2/documents/{identifier}/draft/publish": { + "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { "post": { - "description": "Publish the document's current main (non-branch) draft, promoting it to the published version. No request body — the draft is consumed, so the response echoes the now-published document metadata.\n\nOnly the main draft is publishable here; a branch-attached draft is published by merging its branch (`POST /api/v1/models/{modelId}/branch/{branchName}/merge`), so a document with no main draft returns 404. Documents that require a pull request to publish return 400.", - "operationId": "documentsV2PublishDraft", - "summary": "Publish draft", + "description": "Restore an archived prompt set.", + "operationId": "aiEvalPromptSetsUnarchive", + "summary": "Restore an archived eval prompt set", "tags": [ - "Documents" + "AI Eval" ], "parameters": [ { "schema": { "type": "string", - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "example": "abc123" + "format": "uuid", + "description": "The unique identifier of the eval prompt set.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, "required": true, - "description": "Document identifier — either the URL slug (e.g. `abc123`) or the canonical workbook UUID.", - "name": "identifier", + "description": "The unique identifier of the eval prompt set.", + "name": "promptSetId", "in": "path" } ], "responses": { "200": { - "description": "Draft published successfully.", + "description": "Prompt set restored successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/DocumentsV2PublishDraftResponse" + "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" } } } }, "400": { - "description": "The document requires a pull request to publish (response detail: \"Can't publish because this document can only be edited through a branch\")." + "description": "Invalid `promptSetId` — must be a UUID.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError400" + } + } + } }, "401": { - "description": "Authentication required." + "description": "Missing or invalid API key.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError401" + } + } + } }, "403": { - "description": "Insufficient permissions to publish the draft." - }, - "404": { - "description": "Document not found, or it has no main draft to publish (a branch-attached draft is published by merging its branch)." - }, - "405": { - "description": "Method not allowed." - }, - "409": { - "description": "The target is not a published document." - } - } - } - }, - "/api/v1/embed/sso/generate-session": { - "post": { - "operationId": "embedSsoGenerateSession", - "summary": "Generate embedded SSO session", - "tags": [ - "Embed" - ], - "requestBody": { - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionBody" + "description": "Insufficient permissions.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError403" + } } } - } - }, - "responses": { - "200": { - "description": "Session token generated", + }, + "404": { + "description": "Prompt set not found.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EmbedSsoGenerateSessionResponse" + "$ref": "#/components/schemas/EvalApiError404" } } } - }, - "400": { - "description": "Invalid request body" - }, - "401": { - "description": "Authentication required (API key with embed scope)" - }, - "403": { - "description": "Permission denied - embed not enabled" } } } }, - "/api/v1/ai/eval/prompt-sets": { + "/api/v1/ai/eval/runs": { "get": { - "description": "List eval prompt sets, sorted alphabetically by name. When `model_ids` is omitted, returns prompt sets for every shared model the caller can access. Requires at least the Querier role on each requested model.", - "operationId": "aiEvalPromptSetsList", - "summary": "List eval prompt sets", + "description": "List runs for a prompt set, newest first, filtered to runs whose model the caller can access. The `prompt_set_id` query parameter is required.", + "operationId": "aiEvalRunsList", + "summary": "List eval runs", "tags": [ "AI Eval" ], @@ -35780,42 +36699,40 @@ "true", "false" ], - "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", "example": "false" }, "required": false, - "description": "When `true`, returns archived prompt sets instead of active ones. Defaults to `false`.", + "description": "When `true`, returns archived runs instead of active ones. Defaults to `false`.", "name": "archived", "in": "query" }, { "schema": { - "type": "array", - "items": { - "type": "string", - "format": "uuid" - }, - "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`)." + "type": "string", + "format": "uuid", + "description": "Required — the prompt set whose runs should be listed.", + "example": "550e8400-e29b-41d4-a716-446655440000" }, - "required": false, - "description": "Optional list of model IDs to filter prompt sets by. When omitted, returns prompt sets for every model the caller can access. Supply multiple times to filter by more than one model (e.g., `?model_ids=A&model_ids=B`).", - "name": "model_ids", + "required": true, + "description": "Required — the prompt set whose runs should be listed.", + "name": "prompt_set_id", "in": "query" } ], "responses": { "200": { - "description": "List of prompt sets, sorted alphabetically by name.", + "description": "List of runs for the prompt set.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsListResponse" + "$ref": "#/components/schemas/EvalRunsListResponse" } } } }, "400": { - "description": "Invalid query params (e.g. `model_ids` contains a non-UUID, or `archived` is not `true`/`false`).", + "description": "Missing or invalid `prompt_set_id`.", "content": { "application/json": { "schema": { @@ -35835,7 +36752,7 @@ } }, "403": { - "description": "Insufficient permissions. The caller must have at least the Querier role on each requested model.", + "description": "Insufficient permissions.", "content": { "application/json": { "schema": { @@ -35845,7 +36762,7 @@ } }, "404": { - "description": "No eval-accessible models for this caller.", + "description": "Prompt set not found.", "content": { "application/json": { "schema": { @@ -35857,9 +36774,9 @@ } }, "post": { - "description": "Create a new eval prompt set bound to a shared model. Initial prompts can be supplied; additional prompts can be added later via PATCH.", - "operationId": "aiEvalPromptSetsCreate", - "summary": "Create an eval prompt set", + "description": "Create and start a new run against an existing prompt set. The run enqueues one agentic job per prompt and begins executing immediately. Returns the newly created run with its initial per-prompt result rows.", + "operationId": "aiEvalRunsCreate", + "summary": "Start an eval run", "tags": [ "AI Eval" ], @@ -35868,18 +36785,18 @@ "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsCreateBody" + "$ref": "#/components/schemas/EvalRunsCreateBody" } } } }, "responses": { "201": { - "description": "Prompt set created successfully.", + "description": "Run created and jobs enqueued.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsCreateResponse" + "$ref": "#/components/schemas/EvalRunsCreateResponse" } } } @@ -35905,7 +36822,7 @@ } }, "403": { - "description": "Insufficient permissions. The caller must have at least the Querier role on the model.", + "description": "Insufficient permissions. The caller must have at least the Querier role on the prompt set's model.", "content": { "application/json": { "schema": { @@ -35913,15 +36830,65 @@ } } } + }, + "404": { + "description": "The prompt set was not found, or `run_config.branch_id` does not match an existing branch in the organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError404" + } + } + } + }, + "422": { + "description": "`run_config.branch_id` does not belong to the prompt set's model.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError422" + } + } + } + }, + "429": { + "description": "Per-user active-run cap reached.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError429" + } + } + } + }, + "500": { + "description": "Run created and jobs enqueued, but it could not be re-read for the response. The run exists — list runs for the prompt set to find it rather than retrying, since a retry starts a duplicate run.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError500" + } + } + } + }, + "503": { + "description": "AI eval is paused for this organization.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/EvalApiError503" + } + } + } } } } }, - "/api/v1/ai/eval/prompt-sets/{promptSetId}": { + "/api/v1/ai/eval/runs/{runId}": { "get": { - "description": "Get a single prompt set with all of its prompts.", - "operationId": "aiEvalPromptSetsGet", - "summary": "Get an eval prompt set", + "description": "Get an eval run with every per-prompt result row, including the underlying agentic job state and any scoring data.", + "operationId": "aiEvalRunsGet", + "summary": "Get an eval run", "tags": [ "AI Eval" ], @@ -35930,32 +36897,22 @@ "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", + "description": "The unique identifier of the eval run.", + "name": "runId", "in": "path" } ], "responses": { "200": { - "description": "Prompt set details.", + "description": "Run detail.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsGetResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` — must be a UUID.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" + "$ref": "#/components/schemas/EvalRunsGetResponse" } } } @@ -35981,7 +36938,7 @@ } }, "404": { - "description": "Prompt set not found.", + "description": "Run not found.", "content": { "application/json": { "schema": { @@ -35992,10 +36949,10 @@ } } }, - "patch": { - "description": "Update a prompt set's name, description, and/or prompts. When `prompts` is supplied, it fully replaces the existing list — existing prompts omitted from the list are deleted, entries without an `id` are created, and entries with a matching `id` are updated in place.", - "operationId": "aiEvalPromptSetsUpdate", - "summary": "Update an eval prompt set", + "delete": { + "description": "Archive (soft-delete) an eval run. Any non-terminal per-prompt agentic jobs are cancelled as part of the archive (best-effort), and a still-RUNNING run is flipped to CANCELLED before archival. The call is idempotent; archiving an already-terminal or already-archived run is a no-op.", + "operationId": "aiEvalRunsArchive", + "summary": "Archive an eval run", "tags": [ "AI Eval" ], @@ -36004,42 +36961,22 @@ "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", + "description": "The unique identifier of the eval run.", + "name": "runId", "in": "path" } ], - "requestBody": { - "required": true, - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUpdateBody" - } - } - } - }, "responses": { "200": { - "description": "Prompt set updated successfully.", + "description": "Run archived successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUpdateResponse" - } - } - } - }, - "400": { - "description": "Invalid request body.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalApiError400" + "$ref": "#/components/schemas/EvalRunsDeleteResponse" } } } @@ -36065,7 +37002,7 @@ } }, "404": { - "description": "Prompt set not found.", + "description": "Run not found.", "content": { "application/json": { "schema": { @@ -36074,22 +37011,24 @@ } } }, - "422": { - "description": "A `prompts[].id` in the request does not belong to this prompt set.", + "500": { + "description": "A still-running run may already be flipped to CANCELLED and archived even though the rest of the cascade failed — safe to retry.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalApiError422" + "$ref": "#/components/schemas/EvalApiError500" } } } } } - }, - "delete": { - "description": "Archive (soft-delete) a prompt set. As part of the archive, Omni attempts to cancel every in-flight agentic job associated with the set; the returned `cancelled_job_count` reports how many were cancelled. The archive is committed before run cancellations start. Cancellation is best-effort — the database cancel is authoritative, but the Redis stop-signal that halts a running worker can lag. If the archive itself or a whole run-cancellation fails, the endpoint returns 500, but the prompt set is already archived. The call is idempotent — retrying drains any remaining runs.", - "operationId": "aiEvalPromptSetsArchive", - "summary": "Archive an eval prompt set", + } + }, + "/api/v1/ai/eval/runs/{runId}/cancel": { + "post": { + "description": "Cancel an in-flight eval run. Any non-terminal per-prompt jobs are cancelled and the run is archived — the response returns the updated run inline (`status: CANCELLED`, `is_archived: true`); use `/unarchive` to surface it in the default `archived=false` list again.", + "operationId": "aiEvalRunsCancel", + "summary": "Cancel an eval run", "tags": [ "AI Eval" ], @@ -36098,32 +37037,22 @@ "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", + "description": "The unique identifier of the eval run.", + "name": "runId", "in": "path" } ], "responses": { "200": { - "description": "Prompt set archived successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsDeleteResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` — must be a UUID.", + "description": "Cancellation processed.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalApiError400" + "$ref": "#/components/schemas/EvalRunsCancelResponse" } } } @@ -36149,7 +37078,7 @@ } }, "404": { - "description": "Prompt set not found.", + "description": "Run not found.", "content": { "application/json": { "schema": { @@ -36159,7 +37088,7 @@ } }, "500": { - "description": "Archive committed but a run-cancellation failed; the set is already archived — safe to retry.", + "description": "The run was cancelled and archived, but could not be re-read for the response — safe to retry.", "content": { "application/json": { "schema": { @@ -36171,11 +37100,11 @@ } } }, - "/api/v1/ai/eval/prompt-sets/{promptSetId}/unarchive": { + "/api/v1/ai/eval/runs/{runId}/unarchive": { "post": { - "description": "Restore an archived prompt set.", - "operationId": "aiEvalPromptSetsUnarchive", - "summary": "Restore an archived eval prompt set", + "description": "Restore an archived eval run.", + "operationId": "aiEvalRunsUnarchive", + "summary": "Restore an archived eval run", "tags": [ "AI Eval" ], @@ -36184,32 +37113,22 @@ "schema": { "type": "string", "format": "uuid", - "description": "The unique identifier of the eval prompt set.", - "example": "550e8400-e29b-41d4-a716-446655440000" + "description": "The unique identifier of the eval run.", + "example": "660e8400-e29b-41d4-a716-446655440001" }, "required": true, - "description": "The unique identifier of the eval prompt set.", - "name": "promptSetId", + "description": "The unique identifier of the eval run.", + "name": "runId", "in": "path" } ], "responses": { "200": { - "description": "Prompt set restored successfully.", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/EvalPromptSetsUnarchiveResponse" - } - } - } - }, - "400": { - "description": "Invalid `promptSetId` — must be a UUID.", + "description": "Run restored successfully.", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/EvalApiError400" + "$ref": "#/components/schemas/EvalRunsUnarchiveResponse" } } } @@ -36235,7 +37154,7 @@ } }, "404": { - "description": "Prompt set not found.", + "description": "Run not found.", "content": { "application/json": { "schema": {