{
  "openapi": "3.1.0",
  "info": {
    "title": "Telemetry HTTP API",
    "version": "2026-07-30",
    "description": "Ingest structured events, run synchronous or asynchronous SQL queries, inspect and manage tables, and manage dashboards. Operational guidance and update policy: https://telemetry.sh/docs/api-reference/openapi"
  },
  "servers": [
    {
      "url": "https://api.telemetry.sh",
      "description": "Telemetry API"
    }
  ],
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://telemetry.sh/docs/api-reference/openapi"
  },
  "security": [
    {
      "RawApiKey": []
    },
    {
      "BearerApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Events"
    },
    {
      "name": "Queries"
    },
    {
      "name": "Tables"
    },
    {
      "name": "Dashboards"
    },
    {
      "name": "Legacy"
    }
  ],
  "paths": {
    "/log": {
      "post": {
        "tags": ["Events"],
        "operationId": "logEvents",
        "summary": "Ingest structured events",
        "description": "Accepts one event, a batch of events, or object-encoded JSON strings. Telemetry normalizes the table name, fills a missing timestamp, and prunes null or empty values.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LogRequest"
              },
              "examples": {
                "singleEvent": {
                  "value": {
                    "table": "uber_rides",
                    "data": {
                      "city": "paris",
                      "price": 42
                    }
                  }
                },
                "eventBatch": {
                  "value": {
                    "table": "uber_rides",
                    "data": [
                      {
                        "city": "paris",
                        "price": 42
                      },
                      {
                        "city": "london",
                        "price": 37
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Events accepted for ingestion."
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "5XX": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/query": {
      "post": {
        "tags": ["Queries"],
        "operationId": "runQuery",
        "summary": "Run a synchronous SQL query",
        "description": "Returns result rows inline. Use the asynchronous endpoint for long-running queries or large exports.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/QueryRequest"
              },
              "example": {
                "query": "SELECT city, AVG(price) AS average_price FROM uber_rides GROUP BY city",
                "realtime": true,
                "json": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Query completed.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueryResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "5XX": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/query/async": {
      "post": {
        "tags": ["Queries"],
        "operationId": "startAsyncQuery",
        "summary": "Start an asynchronous SQL query or export",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AsyncQueryRequest"
              },
              "example": {
                "query": "SELECT * FROM uber_rides",
                "realtime": true,
                "json": true,
                "format": "parquet"
              }
            }
          }
        },
        "responses": {
          "202": {
            "description": "Query job accepted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AsyncQueryAccepted"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "$ref": "#/components/responses/PaymentRequired"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "5XX": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/query/async/{job_id}": {
      "get": {
        "tags": ["Queries"],
        "operationId": "getAsyncQueryStatus",
        "summary": "Poll an asynchronous query",
        "parameters": [
          {
            "$ref": "#/components/parameters/JobId"
          }
        ],
        "responses": {
          "200": {
            "description": "Current query status and, when complete, a temporary download URL.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AsyncQueryStatus"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          },
          "5XX": {
            "$ref": "#/components/responses/ServerError"
          }
        }
      }
    },
    "/tables": {
      "get": {
        "tags": ["Tables"],
        "operationId": "listTables",
        "summary": "List tables",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PageSize"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated table names.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TableListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "429": {
            "$ref": "#/components/responses/TooManyRequests"
          }
        }
      }
    },
    "/tables/{table}/schema": {
      "get": {
        "tags": ["Tables"],
        "operationId": "getTableSchema",
        "summary": "Get table schema and lifecycle settings",
        "parameters": [
          {
            "$ref": "#/components/parameters/TableName"
          }
        ],
        "responses": {
          "200": {
            "description": "Parsed schema, retention policy, and partition metadata.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TableSchemaResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/tables/{table}/retention": {
      "patch": {
        "tags": ["Tables"],
        "operationId": "setTableRetention",
        "summary": "Set or clear table retention",
        "parameters": [
          {
            "$ref": "#/components/parameters/TableName"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RetentionRequest"
              },
              "examples": {
                "setRetention": {
                  "value": {
                    "retentionDays": 30
                  }
                },
                "clearRetention": {
                  "value": {
                    "retentionDays": null
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/TableSettings"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/tables/{table}/partition-columns": {
      "patch": {
        "tags": ["Tables"],
        "operationId": "setTablePartitionColumns",
        "summary": "Set or clear table partition columns",
        "parameters": [
          {
            "$ref": "#/components/parameters/TableName"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PartitionColumnsRequest"
              },
              "examples": {
                "setColumns": {
                  "value": {
                    "partitionColumns": ["account_id", "event"]
                  }
                },
                "disablePartitioning": {
                  "value": {
                    "partitionColumns": null
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/TableSettings"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/tables/{table}": {
      "delete": {
        "tags": ["Tables"],
        "operationId": "deleteTable",
        "summary": "Delete a table and all of its data",
        "description": "Permanently deletes the table. Prefer this endpoint over the legacy delete endpoint for whole-table lifecycle operations.",
        "parameters": [
          {
            "$ref": "#/components/parameters/TableName"
          }
        ],
        "responses": {
          "200": {
            "description": "Table deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteTableResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/dashboard": {
      "get": {
        "tags": ["Dashboards"],
        "operationId": "listDashboards",
        "summary": "List dashboards",
        "parameters": [
          {
            "$ref": "#/components/parameters/Page"
          },
          {
            "$ref": "#/components/parameters/PageSize"
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated dashboards with widget records.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DashboardListResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": ["Dashboards"],
        "operationId": "createDashboard",
        "summary": "Create a dashboard",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDashboardRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "$ref": "#/components/responses/DashboardMutation"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      },
      "patch": {
        "tags": ["Dashboards"],
        "operationId": "updateDashboard",
        "summary": "Update a dashboard",
        "description": "Omitted metadata fields remain unchanged. Supplying widgets replaces the complete widget set.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateDashboardRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "$ref": "#/components/responses/DashboardMutation"
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "409": {
            "$ref": "#/components/responses/Conflict"
          }
        }
      },
      "delete": {
        "tags": ["Dashboards"],
        "operationId": "deleteDashboard",
        "summary": "Delete a dashboard and all of its widgets",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DashboardIdentifier"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Dashboard deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeleteDashboardResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/delete": {
      "delete": {
        "tags": ["Legacy"],
        "operationId": "deleteRows",
        "summary": "Delete rows matching a predicate or delete a table",
        "description": "Legacy asynchronous cleanup endpoint. Omitting where deletes the whole table. Prefer DELETE /tables/{table} for whole-table lifecycle operations.",
        "deprecated": true,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LegacyDeleteRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Delete rewrite or table-disable step scheduled.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LegacyDeleteResponse"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "RawApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "Authorization",
        "description": "A Telemetry API key sent as the raw Authorization value."
      },
      "BearerApiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "A Telemetry API key sent as Bearer <key>."
      }
    },
    "parameters": {
      "Page": {
        "name": "page",
        "in": "query",
        "required": false,
        "description": "Positive 1-based page number.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        }
      },
      "PageSize": {
        "name": "pageSize",
        "in": "query",
        "required": false,
        "description": "Positive page size. Values above 100 are clamped to 100. page_size is a legacy alias.",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 50
        }
      },
      "TableName": {
        "name": "table",
        "in": "path",
        "required": true,
        "description": "Canonical table name using lowercase ASCII letters, numbers, and underscores.",
        "schema": {
          "type": "string",
          "pattern": "^[a-z0-9_]+$"
        }
      },
      "JobId": {
        "name": "job_id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        }
      }
    },
    "responses": {
      "BadRequest": {
        "description": "Invalid JSON, SQL, table name, field type, or request shape.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Unauthorized": {
        "description": "API key missing or invalid.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "PaymentRequired": {
        "description": "The account is blocked by a paywall check.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Forbidden": {
        "description": "API key lacks permission for the operation.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "NotFound": {
        "description": "Requested table, query job, dashboard, or route not found.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "Conflict": {
        "description": "The operation conflicts with current state, such as a duplicate dashboard slug.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "TooManyRequests": {
        "description": "Current request rate or account quota exceeded. Respect Retry-After when present.",
        "headers": {
          "Retry-After": {
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "ServerError": {
        "description": "Telemetry could not complete a valid request.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ErrorResponse"
            }
          }
        }
      },
      "TableSettings": {
        "description": "Effective table lifecycle settings.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/TableSettingsResponse"
            }
          }
        }
      },
      "DashboardMutation": {
        "description": "Persisted dashboard and complete widget list.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/DashboardMutationResponse"
            }
          }
        }
      }
    },
    "schemas": {
      "ErrorResponse": {
        "type": "object",
        "additionalProperties": true
      },
      "EventObject": {
        "type": "object",
        "additionalProperties": true
      },
      "LogRequest": {
        "type": "object",
        "required": ["table", "data"],
        "properties": {
          "table": {
            "type": "string",
            "description": "Spaces become underscores and letters are lowercased; the normalized name allows lowercase ASCII letters, numbers, and underscores."
          },
          "data": {
            "description": "One object, an array of objects, one object-encoded JSON string, or an array mixing objects and object-encoded strings.",
            "oneOf": [
              {
                "$ref": "#/components/schemas/EventObject"
              },
              {
                "type": "array",
                "items": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/EventObject"
                    },
                    {
                      "type": "string",
                      "contentMediaType": "application/json"
                    }
                  ]
                }
              },
              {
                "type": "string",
                "contentMediaType": "application/json"
              }
            ]
          }
        },
        "additionalProperties": false
      },
      "QueryRequest": {
        "type": "object",
        "required": ["query"],
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1
          },
          "realtime": {
            "type": "boolean",
            "default": true
          },
          "json": {
            "type": "boolean",
            "default": true
          }
        },
        "additionalProperties": false
      },
      "AsyncQueryRequest": {
        "type": "object",
        "required": ["query"],
        "properties": {
          "query": {
            "type": "string",
            "minLength": 1
          },
          "realtime": {
            "type": "boolean",
            "default": true
          },
          "json": {
            "type": "boolean",
            "default": true
          },
          "format": {
            "type": "string",
            "enum": ["json", "parquet"],
            "default": "json"
          }
        },
        "additionalProperties": false
      },
      "QueryResponse": {
        "type": "object",
        "required": ["status", "data", "key_order"],
        "properties": {
          "status": {
            "const": "success"
          },
          "data": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": true
            }
          },
          "key_order": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        },
        "additionalProperties": true
      },
      "AsyncQueryAccepted": {
        "type": "object",
        "required": ["status", "job_id", "format", "status_url"],
        "properties": {
          "status": {
            "const": "accepted"
          },
          "job_id": {
            "type": "string"
          },
          "format": {
            "type": "string",
            "enum": ["json", "parquet"]
          },
          "status_url": {
            "type": "string"
          }
        }
      },
      "AsyncQueryStatus": {
        "type": "object",
        "required": ["status", "job_id", "query_status", "format"],
        "properties": {
          "status": {
            "const": "success"
          },
          "job_id": {
            "type": "string"
          },
          "query_status": {
            "type": "string",
            "enum": ["queued", "running", "completed", "failed"]
          },
          "format": {
            "type": "string",
            "enum": ["json", "parquet"]
          },
          "progress_pct": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "message": {
            "type": "string"
          },
          "error": {
            "type": "string"
          },
          "created_at": {
            "type": "string"
          },
          "completed_at": {
            "type": ["string", "null"]
          },
          "download_url": {
            "type": "string",
            "format": "uri"
          },
          "download_url_expires_in_seconds": {
            "type": "integer",
            "minimum": 0
          }
        },
        "additionalProperties": true
      },
      "Pagination": {
        "type": "object",
        "required": ["page", "pageSize", "total", "totalPages", "hasNextPage", "hasPreviousPage"],
        "properties": {
          "page": {
            "type": "integer"
          },
          "pageSize": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          },
          "totalPages": {
            "type": "integer"
          },
          "hasNextPage": {
            "type": "boolean"
          },
          "hasPreviousPage": {
            "type": "boolean"
          }
        }
      },
      "TableListResponse": {
        "type": "object",
        "required": ["status", "pagination", "tables"],
        "properties": {
          "status": {
            "const": "success"
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "tables": {
            "type": "array",
            "items": {
              "type": "string"
            }
          }
        }
      },
      "TableSchemaResponse": {
        "type": "object",
        "required": ["status", "table", "schema"],
        "properties": {
          "status": {
            "const": "success"
          },
          "table": {
            "type": "string"
          },
          "schema": {
            "type": "object",
            "additionalProperties": true
          },
          "retention_days": {
            "type": ["integer", "null"]
          },
          "partition_columns": {
            "type": ["array", "null"],
            "items": {
              "type": "string"
            }
          },
          "partition_spec_version": {
            "type": ["integer", "null"]
          }
        },
        "additionalProperties": true
      },
      "RetentionRequest": {
        "type": "object",
        "properties": {
          "retentionDays": {
            "type": ["integer", "null"],
            "minimum": 1
          },
          "retention_days": {
            "type": ["integer", "null"],
            "minimum": 1,
            "deprecated": true
          }
        },
        "additionalProperties": false
      },
      "PartitionColumnsRequest": {
        "type": "object",
        "properties": {
          "partitionColumns": {
            "type": ["array", "null"],
            "items": {
              "type": "string",
              "minLength": 1
            }
          },
          "partition_columns": {
            "type": ["array", "null"],
            "items": {
              "type": "string",
              "minLength": 1
            },
            "deprecated": true
          }
        },
        "additionalProperties": false
      },
      "TableSettingsResponse": {
        "type": "object",
        "required": ["status", "table"],
        "properties": {
          "status": {
            "const": "success"
          },
          "table": {
            "type": "string"
          },
          "retention_days": {
            "type": ["integer", "null"]
          },
          "partition_columns": {
            "type": ["array", "null"],
            "items": {
              "type": "string"
            }
          },
          "partition_spec_version": {
            "type": ["integer", "null"]
          }
        }
      },
      "DeleteTableResponse": {
        "type": "object",
        "required": ["status", "deleted_table"],
        "properties": {
          "status": {
            "const": "success"
          },
          "deleted_table": {
            "type": "object",
            "required": ["name"],
            "properties": {
              "name": {
                "type": "string"
              }
            }
          }
        }
      },
      "DashboardIdentifier": {
        "type": "object",
        "properties": {
          "dashboardId": {
            "type": "string"
          },
          "dashboardSlug": {
            "type": "string"
          }
        },
        "anyOf": [
          {
            "required": ["dashboardId"]
          },
          {
            "required": ["dashboardSlug"]
          }
        ],
        "additionalProperties": false
      },
      "DashboardWidget": {
        "type": "object",
        "required": ["title", "widget_type", "config"],
        "properties": {
          "id": {
            "type": "string",
            "readOnly": true
          },
          "title": {
            "type": "string",
            "minLength": 1
          },
          "widget_type": {
            "type": "string",
            "enum": ["query", "explorer", "header", "free_text"]
          },
          "config": {
            "type": "object",
            "additionalProperties": true
          },
          "layout": {
            "type": "object",
            "properties": {
              "x": {
                "type": "integer"
              },
              "y": {
                "type": "integer"
              },
              "w": {
                "type": "integer"
              },
              "h": {
                "type": "integer"
              }
            },
            "additionalProperties": false
          },
          "sort_order": {
            "type": "integer",
            "readOnly": true
          }
        },
        "additionalProperties": true
      },
      "CreateDashboardRequest": {
        "type": "object",
        "required": ["name"],
        "properties": {
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": ["string", "null"]
          },
          "widgets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DashboardWidget"
            },
            "default": []
          }
        },
        "additionalProperties": false
      },
      "UpdateDashboardRequest": {
        "type": "object",
        "properties": {
          "dashboardId": {
            "type": "string"
          },
          "dashboardSlug": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "minLength": 1
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": ["string", "null"]
          },
          "widgets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DashboardWidget"
            },
            "description": "Full replacement widget list."
          }
        },
        "anyOf": [
          {
            "required": ["dashboardId"]
          },
          {
            "required": ["dashboardSlug"]
          }
        ],
        "additionalProperties": false
      },
      "DashboardRecord": {
        "type": "object",
        "required": ["id", "team_id", "name", "slug", "created_at", "updated_at", "url"],
        "properties": {
          "id": {
            "type": "string"
          },
          "team_id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "description": {
            "type": ["string", "null"]
          },
          "created_by": {
            "type": ["string", "null"]
          },
          "created_by_api_key_id": {
            "type": ["string", "null"]
          },
          "created_at": {
            "type": "string"
          },
          "updated_at": {
            "type": "string"
          },
          "url": {
            "type": "string"
          },
          "widget_count": {
            "type": "integer"
          },
          "widgets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DashboardWidget"
            }
          }
        },
        "additionalProperties": true
      },
      "DashboardListResponse": {
        "type": "object",
        "required": ["status", "pagination", "dashboards"],
        "properties": {
          "status": {
            "const": "success"
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "dashboards": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DashboardRecord"
            }
          }
        }
      },
      "DashboardMutationResponse": {
        "type": "object",
        "required": ["status", "dashboard", "widgets"],
        "properties": {
          "status": {
            "const": "success"
          },
          "dashboard": {
            "$ref": "#/components/schemas/DashboardRecord"
          },
          "widgets": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/DashboardWidget"
            }
          }
        }
      },
      "DeleteDashboardResponse": {
        "type": "object",
        "required": ["status", "deleted_dashboard"],
        "properties": {
          "status": {
            "const": "success"
          },
          "deleted_dashboard": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "LegacyDeleteRequest": {
        "type": "object",
        "required": ["table"],
        "properties": {
          "table": {
            "type": "string"
          },
          "where": {
            "type": "string",
            "description": "SQL condition selecting rows. Omitting this field deletes the entire table."
          }
        },
        "additionalProperties": false
      },
      "LegacyDeleteResponse": {
        "type": "object",
        "required": ["status", "message"],
        "properties": {
          "status": {
            "const": "success"
          },
          "message": {
            "type": "string"
          }
        }
      }
    }
  }
}
