{
  "openapi": "3.1.0",
  "info": {
    "title": "datatomcp REST API",
    "version": "2026-11-04",
    "summary": "The AI-native data layer for teams without a data team.",
    "description": "Query your team's CSVs, Excel files and Google Sheets with exact, versioned results, shared definitions and charts. The same engine serves the MCP server at https://app.datatomcp.com/mcp. Reference: https://datatomcp.com/docs/api",
    "contact": {
      "name": "datatomcp",
      "email": "hello@datatomcp.com",
      "url": "https://datatomcp.com"
    },
    "termsOfService": "https://datatomcp.com/terms"
  },
  "servers": [
    {
      "url": "https://app.datatomcp.com/v1"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "tags": [
    {
      "name": "Datasets",
      "description": "Add, describe, refresh, change and remove datasets."
    },
    {
      "name": "Query",
      "description": "Rows and totals, distinct values and versions. One engine shared with the MCP server."
    },
    {
      "name": "Definitions",
      "description": "Saved metrics and the glossary agents read."
    },
    {
      "name": "Charts",
      "description": "A chart from a query, or from your own chart spec."
    },
    {
      "name": "Dashboards",
      "description": "Stories (slides) and boards (one page) built from queries; refresh re-runs them exactly."
    },
    {
      "name": "Account",
      "description": "Workspaces and usage."
    }
  ],
  "paths": {
    "/datasets": {
      "get": {
        "tags": [
          "Datasets"
        ],
        "summary": "List datasets",
        "description": "Datasets of every workspace the key can reach.",
        "parameters": [
          {
            "name": "workspace_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Only this workspace."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "datasets": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DatasetSummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "Datasets"
        ],
        "summary": "Add a dataset",
        "description": "Upload a CSV or Excel file (raw body or multipart field `file`), or send JSON with a public CSV link or a Google Sheet you shared through the app.",
        "parameters": [
          {
            "name": "workspace_id",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Upload only: the target workspace."
          },
          {
            "name": "sheet",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Upload only: which Excel sheet."
          }
        ],
        "requestBody": {
          "content": {
            "text/csv": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            },
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              }
            },
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "source_url": {
                    "type": "string",
                    "maxLength": 2048,
                    "description": "A public CSV or Excel link (Google Sheets publish link, Dropbox, S3...)."
                  },
                  "google_sheet": {
                    "type": "object",
                    "properties": {
                      "spreadsheet_id": {
                        "type": "string"
                      },
                      "sheet_id": {
                        "type": "integer"
                      }
                    }
                  },
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "workspace_id": {
                    "type": "string"
                  },
                  "sheet": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dataset"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "413": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        }
      ],
      "get": {
        "tags": [
          "Datasets"
        ],
        "summary": "Describe a dataset",
        "description": "Columns with types and examples, the import report, links, definitions and glossary.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dataset"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "patch": {
        "tags": [
          "Datasets"
        ],
        "summary": "Rename, switch auto-sync or change column types",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "maxLength": 120
                  },
                  "auto_sync": {
                    "type": "boolean",
                    "description": "Google Sheets and links: sync within minutes (Pro)."
                  },
                  "column_types": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "object",
                      "properties": {
                        "type": {
                          "type": "string"
                        },
                        "clean": {
                          "type": "string",
                          "enum": [
                            "numeric"
                          ]
                        }
                      }
                    },
                    "description": "Re-imports the data with these types."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dataset"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "Datasets"
        ],
        "summary": "Delete a dataset",
        "description": "Owners and editors only. Removes every version.",
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/refresh": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        }
      ],
      "post": {
        "tags": [
          "Datasets"
        ],
        "summary": "Refresh from the source",
        "description": "Links and Google Sheets are fetched again. Uploads take the new file as the body, like POST /datasets. Each refresh is a new version.",
        "requestBody": {
          "required": false,
          "content": {
            "text/csv": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Dataset"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/docs.md": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        }
      ],
      "get": {
        "tags": [
          "Datasets"
        ],
        "summary": "Dataset docs as Markdown",
        "description": "Columns, definitions and example calls, ready to paste into an agent's instructions.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "text/markdown": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/query": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        }
      ],
      "post": {
        "tags": [
          "Query"
        ],
        "summary": "Query rows or totals",
        "description": "Without metrics: rows. With metrics: totals, per group with group_by. Saved definitions are used as { \"metric\": \"name\" }. Every call is recorded in the workspace audit.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/Query"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/QueryResult"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/values/{column}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        },
        {
          "name": "column",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Column id."
        }
      ],
      "get": {
        "tags": [
          "Query"
        ],
        "summary": "Distinct values of a column",
        "description": "The real values with their counts, so filters match \"France\" and not \"FR\".",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 500,
              "default": 50
            }
          },
          {
            "name": "version",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1
            },
            "description": "Read an older version still kept (GET /datasets/{id}/versions)."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "column": {
                      "type": "string"
                    },
                    "values": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      },
                      "description": "Each value with its row count, most frequent first."
                    },
                    "distinct_total": {
                      "type": "integer"
                    },
                    "truncated": {
                      "type": "boolean"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/versions": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        }
      ],
      "get": {
        "tags": [
          "Query"
        ],
        "summary": "Versions still kept",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "dataset_id": {
                      "type": "string"
                    },
                    "current_version": {
                      "type": "integer"
                    },
                    "versions": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/metrics": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        }
      ],
      "get": {
        "tags": [
          "Definitions"
        ],
        "summary": "Definitions of a dataset",
        "parameters": [
          {
            "name": "drafts",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Include drafts waiting for approval."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "dataset_id": {
                      "type": "string"
                    },
                    "metrics": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Definition"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/metrics/{name}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        },
        {
          "name": "name",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "snake_case name, like paid_revenue."
        }
      ],
      "put": {
        "tags": [
          "Definitions"
        ],
        "summary": "Add or replace a definition",
        "description": "Editors only. A definition saved over the API is approved by the key's owner.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DefinitionInput"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replaced",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Definition"
                }
              }
            }
          },
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Definition"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "Definitions"
        ],
        "summary": "Remove a definition",
        "responses": {
          "204": {
            "description": "Removed"
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/metrics/{name}/approve": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        },
        {
          "name": "name",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Name of a drafted definition."
        }
      ],
      "post": {
        "tags": [
          "Definitions"
        ],
        "summary": "Approve a draft",
        "description": "Editors only. From then on agents get it, with the approver's name.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Definition"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/columns/{column}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        },
        {
          "name": "column",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Column id."
        }
      ],
      "put": {
        "tags": [
          "Datasets"
        ],
        "summary": "Describe a column",
        "description": "Editors only. What the column means, its unit, its role and whether it adds up. Kept across refreshes; agents read it in describe_dataset and the answers' units.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ColumnMeaning"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "allOf": [
                    {
                      "$ref": "#/components/schemas/ColumnMeaning"
                    },
                    {
                      "type": "object",
                      "properties": {
                        "column": {
                          "type": "string"
                        },
                        "described_by": {
                          "type": "string"
                        }
                      }
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "Datasets"
        ],
        "summary": "Back to the drafted meaning",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ColumnMeaning"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/workspaces/{id}/overview": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Workspace id, from GET /workspaces."
        }
      ],
      "get": {
        "tags": [
          "Definitions"
        ],
        "summary": "What a workspace can answer",
        "description": "Every dataset with a one-line description, its columns' meanings and freshness; the approved definitions; the links between datasets; the glossary; and five example questions with the exact call that answers each. Same as the MCP workspace_overview tool.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "today": {
                      "type": "string",
                      "format": "date"
                    },
                    "datasets": {
                      "type": "array",
                      "items": {
                        "type": "object"
                      }
                    },
                    "definitions": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Definition"
                      }
                    },
                    "glossary": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/GlossaryTerm"
                      }
                    },
                    "example_questions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "question": {
                            "type": "string"
                          },
                          "tool": {
                            "type": "string"
                          },
                          "arguments": {
                            "type": "object"
                          }
                        }
                      }
                    },
                    "how_to_answer": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/workspaces/{id}/definitions": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Workspace id, from GET /workspaces."
        }
      ],
      "get": {
        "tags": [
          "Definitions"
        ],
        "summary": "All definitions and the glossary of a workspace",
        "parameters": [
          {
            "name": "drafts",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ]
            },
            "description": "Include drafts waiting for approval."
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspace_id": {
                      "type": "string"
                    },
                    "metrics": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Definition"
                      }
                    },
                    "glossary": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/GlossaryTerm"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/datasets/{id}/chart": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dataset id, from GET /datasets."
        }
      ],
      "post": {
        "tags": [
          "Charts"
        ],
        "summary": "Chart from a query",
        "description": "Runs the query like /query (same checks, same audit), then draws its rows.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "allOf": [
                  {
                    "$ref": "#/components/schemas/ChartOptions"
                  },
                  {
                    "type": "object",
                    "properties": {
                      "query": {
                        "$ref": "#/components/schemas/Query"
                      },
                      "version": {
                        "type": "integer"
                      }
                    }
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "JSON with spec, svg and meta; or, with output set, the SVG, HTML figure, spec or CSV alone.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "spec": {
                      "type": "object"
                    },
                    "svg": {
                      "type": "string"
                    },
                    "meta": {
                      "$ref": "#/components/schemas/Meta"
                    }
                  }
                }
              },
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              },
              "text/html": {
                "schema": {
                  "type": "string"
                }
              },
              "text/csv": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/charts/render": {
      "post": {
        "tags": [
          "Charts"
        ],
        "summary": "Draw your own chart spec",
        "description": "Any of the 52 chart types of @datatomcp/charts from a spec you send. No data access.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "spec"
                ],
                "properties": {
                  "spec": {
                    "type": "object"
                  },
                  "theme": {
                    "type": "string",
                    "enum": [
                      "datatomcp-dark",
                      "datatomcp-light",
                      "editorial-light",
                      "editorial-dark",
                      "brand-light",
                      "brand-dark"
                    ]
                  },
                  "width": {
                    "type": "integer"
                  },
                  "output": {
                    "type": "string",
                    "enum": [
                      "svg",
                      "figure",
                      "csv"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The drawn chart",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/dashboards": {
      "get": {
        "tags": [
          "Dashboards"
        ],
        "summary": "List dashboards",
        "description": "The dashboards of a workspace (the current one when workspace_id is left out), with owner, type and last refresh.",
        "parameters": [
          {
            "name": "workspace_id",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspace_id": {
                      "type": "string"
                    },
                    "dashboards": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/DashboardSummary"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "post": {
        "tags": [
          "Dashboards"
        ],
        "summary": "Create a dashboard",
        "description": "A story takes slides, each with an optional title and blocks; a board takes blocks. Blocks: chart { dataset_id, query, chart }, kpi { dataset_id, query: { metrics }, title }, text { text }, commentary { prompt } (written from the numbers on your own AI key at each refresh), shape { shape }. Layout is optional: blocks are placed for you. Charts are drawn at once. Only the workspace's own datasets can be used.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DashboardInput"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "workspaceId": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string"
                    },
                    "refresh": {
                      "$ref": "#/components/schemas/Refresh"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/dashboards/{id}": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dashboard id, from GET /dashboards."
        }
      ],
      "get": {
        "tags": [
          "Dashboards"
        ],
        "summary": "Read a dashboard",
        "description": "Its blocks with their drawn chart specs, comments and who is editing what.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      },
      "delete": {
        "tags": [
          "Dashboards"
        ],
        "summary": "Delete a dashboard",
        "description": "Only the person who made it, or the workspace owner.",
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/dashboards/{id}/refresh": {
      "parameters": [
        {
          "name": "id",
          "in": "path",
          "required": true,
          "schema": {
            "type": "string"
          },
          "description": "Dashboard id."
        }
      ],
      "post": {
        "tags": [
          "Dashboards"
        ],
        "summary": "Refresh a dashboard",
        "description": "Re-runs every saved query on the latest data, exactly; no AI key needed. Commentary is rewritten on your own AI key (Account → AI models); without one it keeps its last text and the answer says \"API key not provided\". Every refresh shows in Audit → Dashboard refreshes.",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Refresh"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/workspaces": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Workspaces the key can reach",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspaces": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "role": {
                            "type": "string",
                            "enum": [
                              "owner",
                              "editor",
                              "viewer"
                            ]
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    },
    "/usage": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Today's usage",
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "date": {
                      "type": "string",
                      "format": "date"
                    },
                    "queries": {
                      "type": "integer"
                    },
                    "rows_returned": {
                      "type": "integer"
                    },
                    "queries_limit": {
                      "type": "integer"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/Error"
          },
          "401": {
            "$ref": "#/components/responses/Error"
          },
          "403": {
            "$ref": "#/components/responses/Error"
          },
          "404": {
            "$ref": "#/components/responses/Error"
          },
          "429": {
            "$ref": "#/components/responses/Error"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from Account → API keys in the app. It starts with dtm_ and can be limited to some workspaces."
      }
    },
    "responses": {
      "Error": {
        "description": "Error",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "DashboardInput": {
        "type": "object",
        "required": [
          "type",
          "title"
        ],
        "properties": {
          "workspace_id": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "story",
              "board"
            ]
          },
          "title": {
            "type": "string",
            "maxLength": 200
          },
          "subtitle": {
            "type": "string",
            "maxLength": 300
          },
          "mode": {
            "type": "string",
            "enum": [
              "light",
              "dark"
            ]
          },
          "slides": {
            "type": "array",
            "maxItems": 40,
            "items": {
              "type": "object",
              "properties": {
                "title": {
                  "type": "string"
                },
                "subtitle": {
                  "type": "string"
                },
                "blocks": {
                  "type": "array",
                  "maxItems": 12,
                  "items": {
                    "type": "object",
                    "required": [
                      "kind"
                    ],
                    "properties": {
                      "kind": {
                        "type": "string",
                        "enum": [
                          "chart",
                          "kpi",
                          "text",
                          "commentary",
                          "shape"
                        ]
                      },
                      "dataset_id": {
                        "type": "string"
                      },
                      "query": {
                        "$ref": "#/components/schemas/Query"
                      },
                      "chart": {
                        "type": "object",
                        "description": "As POST /datasets/{id}/chart takes it: chart, x, y, title, grain, …"
                      },
                      "title": {
                        "type": "string"
                      },
                      "text": {
                        "type": "string"
                      },
                      "prompt": {
                        "type": "string",
                        "description": "Commentary: what to comment on."
                      },
                      "shape": {
                        "type": "string",
                        "enum": [
                          "rect",
                          "ellipse",
                          "line",
                          "arrow"
                        ]
                      },
                      "layout": {
                        "type": "object",
                        "description": "Story: x, y, w, h in percent of a 16:9 slide. Board: x, w in 12 columns; y, h in rows."
                      },
                      "style": {
                        "type": "object",
                        "description": "fontSize, titleSize, subtitleSize, color, fill, stroke, align, weight."
                      }
                    }
                  }
                }
              }
            }
          },
          "blocks": {
            "type": "array",
            "maxItems": 60,
            "items": {
              "type": "object",
              "required": [
                "kind"
              ],
              "properties": {
                "kind": {
                  "type": "string",
                  "enum": [
                    "chart",
                    "kpi",
                    "text",
                    "commentary",
                    "shape"
                  ]
                },
                "dataset_id": {
                  "type": "string"
                },
                "query": {
                  "$ref": "#/components/schemas/Query"
                },
                "chart": {
                  "type": "object",
                  "description": "As POST /datasets/{id}/chart takes it: chart, x, y, title, grain, …"
                },
                "title": {
                  "type": "string"
                },
                "text": {
                  "type": "string"
                },
                "prompt": {
                  "type": "string",
                  "description": "Commentary: what to comment on."
                },
                "shape": {
                  "type": "string",
                  "enum": [
                    "rect",
                    "ellipse",
                    "line",
                    "arrow"
                  ]
                },
                "layout": {
                  "type": "object",
                  "description": "Story: x, y, w, h in percent of a 16:9 slide. Board: x, w in 12 columns; y, h in rows."
                },
                "style": {
                  "type": "object",
                  "description": "fontSize, titleSize, subtitleSize, color, fill, stroke, align, weight."
                }
              }
            }
          }
        }
      },
      "DashboardSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "enum": [
              "story",
              "board"
            ]
          },
          "owner": {
            "type": "string"
          },
          "refreshedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "url": {
            "type": "string"
          }
        }
      },
      "Refresh": {
        "type": "object",
        "properties": {
          "queries": {
            "type": "integer"
          },
          "errors": {
            "type": "integer"
          },
          "commentary": {
            "type": "string",
            "enum": [
              "none",
              "updated",
              "no_key",
              "failed"
            ]
          },
          "refreshedAt": {
            "type": "string",
            "format": "date-time"
          },
          "note": {
            "type": "string"
          }
        }
      },
      "Filter": {
        "type": "object",
        "required": [
          "column",
          "op"
        ],
        "properties": {
          "column": {
            "type": "string",
            "description": "A column of the dataset, or alias.column of a linked dataset."
          },
          "op": {
            "type": "string",
            "enum": [
              "eq",
              "neq",
              "gt",
              "gte",
              "lt",
              "lte",
              "in",
              "not_in",
              "contains",
              "starts_with",
              "is_null",
              "not_null",
              "between"
            ],
            "description": "between takes [low, high] and includes both ends; in and not_in take an array; contains and starts_with ignore case."
          },
          "value": {
            "description": "A string, number or boolean, or an array of up to 100 of them. Omit for is_null and not_null."
          }
        }
      },
      "Metric": {
        "type": "object",
        "description": "Either fn (with column) or the name of a saved metric, not both.",
        "properties": {
          "fn": {
            "type": "string",
            "enum": [
              "count",
              "count_distinct",
              "sum",
              "avg",
              "min",
              "max"
            ]
          },
          "column": {
            "type": "string",
            "description": "Not needed for count."
          },
          "as": {
            "type": "string",
            "pattern": "^[a-z_][a-z0-9_]{0,62}$",
            "description": "Name of the result column."
          },
          "where": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/Filter"
            },
            "description": "Only rows matching these filters count toward this metric."
          },
          "metric": {
            "type": "string",
            "maxLength": 63,
            "description": "A saved, approved definition of the dataset, by name."
          }
        }
      },
      "Query": {
        "type": "object",
        "additionalProperties": false,
        "description": "A constrained JSON query. Column names are checked against the schema, values are bound as parameters, and every query has a limit and a timeout.",
        "properties": {
          "select": {
            "type": "array",
            "maxItems": 200,
            "items": {
              "type": "string"
            },
            "description": "Columns to return (rows mode). Leave out for all columns."
          },
          "where": {
            "type": "array",
            "maxItems": 30,
            "items": {
              "$ref": "#/components/schemas/Filter"
            }
          },
          "group_by": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "string"
            }
          },
          "grain": {
            "type": "string",
            "enum": [
              "day",
              "week",
              "month",
              "quarter",
              "year"
            ],
            "description": "Group date and timestamp columns in group_by by this period (weeks start on Monday). Each group is labelled with the period's first day."
          },
          "metrics": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/Metric"
            },
            "description": "With metrics the query returns totals, per group when group_by is set."
          },
          "order_by": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "object",
              "required": [
                "column"
              ],
              "properties": {
                "column": {
                  "type": "string"
                },
                "dir": {
                  "type": "string",
                  "enum": [
                    "asc",
                    "desc"
                  ],
                  "default": "asc"
                }
              }
            }
          },
          "limit": {
            "type": "integer",
            "minimum": 1,
            "maximum": 1000,
            "default": 100
          },
          "offset": {
            "type": "integer",
            "minimum": 0,
            "maximum": 100000,
            "default": 0
          },
          "version": {
            "type": "integer",
            "description": "Pin the query to a dataset version, so follow-up calls read the same data."
          }
        }
      },
      "Meta": {
        "type": "object",
        "description": "Sent with every result, so an answer can be traced back to its data.",
        "properties": {
          "dataset_id": {
            "type": "string"
          },
          "version": {
            "type": "integer",
            "description": "The dataset version the result came from."
          },
          "refreshed_at": {
            "type": "string",
            "format": "date-time"
          },
          "rows_returned": {
            "type": "integer"
          },
          "rows_matched": {
            "type": "integer"
          },
          "truncated": {
            "type": "boolean",
            "description": "True when more rows matched than the limit returned."
          },
          "query": {
            "$ref": "#/components/schemas/Query"
          },
          "metrics": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "The saved definitions the query used, with who approved them."
          },
          "linked": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "dataset_id": {
                  "type": "string"
                },
                "version": {
                  "type": "integer"
                },
                "via": {
                  "type": "string"
                }
              }
            }
          },
          "unmatched": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "via": {
                  "type": "string"
                },
                "rows": {
                  "type": "integer"
                }
              }
            },
            "description": "Rows whose link value found no row in the linked dataset."
          },
          "view_url": {
            "type": "string",
            "format": "uri",
            "description": "A page where a person can check the rows behind the number."
          },
          "rows_counted": {
            "type": "integer",
            "description": "Totals: rows of the dataset the numbers were computed over, after the filters."
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Unit per result column, from the definition or the column's meaning."
          },
          "method": {
            "type": "string",
            "description": "How the numbers were computed, in one line."
          },
          "freshness": {
            "$ref": "#/components/schemas/Freshness"
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "What affects the number: duplicate rows, empty values in the columns used, sums of columns that don't add up."
          }
        }
      },
      "QueryResult": {
        "type": "object",
        "properties": {
          "rows": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "meta": {
            "$ref": "#/components/schemas/Meta"
          }
        }
      },
      "DatasetSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "workspace": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              }
            }
          },
          "rows": {
            "type": "integer"
          },
          "columns": {
            "type": "integer"
          },
          "version": {
            "type": "integer"
          },
          "refreshed_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Column": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "The name to use in queries."
          },
          "name": {
            "type": "string",
            "description": "The header as it was in the file."
          },
          "type": {
            "type": "string",
            "enum": [
              "integer",
              "number",
              "boolean",
              "date",
              "timestamp",
              "text"
            ]
          },
          "description": {
            "type": "string",
            "description": "What one value means, drafted on import (or by the cleaning model where the workspace turned AI on) and editable."
          },
          "unit": {
            "type": "string",
            "description": "EUR, %, days, units… Missing when the column has none."
          },
          "role": {
            "type": "string",
            "enum": [
              "id",
              "date",
              "dimension",
              "metric"
            ]
          },
          "summable": {
            "type": "boolean",
            "description": "Whether a sum over rows means something. False for prices, rates, balances and percentages."
          },
          "described_by": {
            "type": "string",
            "enum": [
              "datatomcp",
              "ai",
              "person"
            ],
            "description": "Who wrote the description: the import draft, the cleaning model, or someone on the team."
          },
          "min": {
            "description": "Smallest value, for numbers and dates."
          },
          "max": {
            "description": "Largest value, for numbers and dates."
          },
          "nullable": {
            "type": "boolean"
          },
          "null_count": {
            "type": "integer"
          },
          "distinct_count": {
            "type": "integer"
          },
          "examples": {
            "type": "array",
            "items": {}
          }
        }
      },
      "Dataset": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "source": {
            "type": "object",
            "properties": {
              "type": {
                "type": "string",
                "enum": [
                  "upload",
                  "url",
                  "google_sheet"
                ]
              },
              "url": {
                "type": "string"
              },
              "last_error": {
                "type": "string"
              },
              "auto_sync": {
                "type": "boolean"
              },
              "last_checked_at": {
                "type": "string",
                "format": "date-time"
              }
            }
          },
          "row_count": {
            "type": "integer"
          },
          "columns": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Column"
            }
          },
          "quality": {
            "type": "object",
            "description": "The import report: warnings, rejected rows with samples, type conversions, exact duplicate rows and empty values per column.",
            "properties": {
              "warnings": {
                "type": "array",
                "items": {}
              },
              "rejected_rows": {
                "type": "integer"
              },
              "rejected_samples": {
                "type": "array",
                "items": {}
              },
              "conversions": {
                "type": "array",
                "items": {}
              },
              "duplicate_rows": {
                "type": "integer"
              },
              "empty_values": {
                "type": "object",
                "additionalProperties": {
                  "type": "integer"
                }
              }
            }
          },
          "freshness": {
            "$ref": "#/components/schemas/Freshness"
          },
          "links": {
            "type": "array",
            "description": "Linked datasets whose columns this one can use as use_as.column.",
            "items": {
              "type": "object",
              "properties": {
                "use_as": {
                  "type": "string"
                },
                "on": {
                  "type": "string"
                },
                "via": {
                  "type": "string"
                },
                "kind": {
                  "type": "string"
                },
                "dataset_id": {
                  "type": "string"
                },
                "columns": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                }
              }
            }
          },
          "metrics": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Definition"
            }
          },
          "glossary": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/GlossaryTerm"
            }
          }
        }
      },
      "Definition": {
        "type": "object",
        "description": "A saved metric: the team's agreed meaning of a number.",
        "properties": {
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "fn": {
            "type": "string",
            "enum": [
              "count",
              "count_distinct",
              "sum",
              "avg",
              "min",
              "max"
            ]
          },
          "column": {
            "type": "string"
          },
          "where": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Filter"
            }
          },
          "status": {
            "type": "string",
            "enum": [
              "approved",
              "draft"
            ]
          },
          "approved_by": {
            "type": "string"
          },
          "aliases": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "unit": {
            "type": "string"
          },
          "direction": {
            "type": "string",
            "enum": [
              "higher_is_better",
              "lower_is_better"
            ],
            "description": "Whether a rise is good news. Charts colour variances by it."
          },
          "ties_out": {
            "type": "string",
            "description": "A check the data confirms, like \"quantity × unit_price = amount on 4,990 of 5,000 rows\"."
          },
          "broken": {
            "type": "string",
            "description": "Set when a column the definition uses is gone."
          }
        }
      },
      "Freshness": {
        "type": "object",
        "properties": {
          "refreshed_at": {
            "type": "string",
            "format": "date-time"
          },
          "age_hours": {
            "type": "number"
          },
          "summary": {
            "type": "string"
          },
          "source_checked_at": {
            "type": "string",
            "format": "date-time"
          },
          "last_refresh_failed": {
            "type": "boolean"
          }
        }
      },
      "ColumnMeaning": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "description": {
            "type": "string",
            "maxLength": 300
          },
          "unit": {
            "type": [
              "string",
              "null"
            ],
            "maxLength": 40
          },
          "role": {
            "type": "string",
            "enum": [
              "id",
              "date",
              "dimension",
              "metric"
            ],
            "description": "metric needs a number column."
          },
          "summable": {
            "type": "boolean"
          }
        }
      },
      "DefinitionInput": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "fn"
        ],
        "properties": {
          "description": {
            "type": "string",
            "maxLength": 500
          },
          "fn": {
            "type": "string",
            "enum": [
              "count",
              "count_distinct",
              "sum",
              "avg",
              "min",
              "max"
            ]
          },
          "column": {
            "type": "string",
            "maxLength": 200
          },
          "where": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "$ref": "#/components/schemas/Filter"
            }
          },
          "unit": {
            "type": "string",
            "maxLength": 40
          },
          "aliases": {
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "string"
            },
            "description": "Other names that answer to this definition, like sales."
          },
          "direction": {
            "type": "string",
            "enum": [
              "higher_is_better",
              "lower_is_better"
            ],
            "description": "Guessed from the name when left out (costs and churn: lower is better)."
          }
        }
      },
      "GlossaryTerm": {
        "type": "object",
        "properties": {
          "term": {
            "type": "string"
          },
          "meaning": {
            "type": "string"
          }
        }
      },
      "ChartOptions": {
        "type": "object",
        "required": [
          "chart"
        ],
        "properties": {
          "chart": {
            "type": "string",
            "enum": [
              "line",
              "area",
              "columns",
              "bar",
              "donut",
              "treemap",
              "waffle",
              "funnel",
              "pareto",
              "scatter",
              "heatmap",
              "histogram",
              "kpi",
              "table",
              "variance",
              "bullet",
              "waterfall",
              "scorecard",
              "combo",
              "radar",
              "candlestick",
              "gauge",
              "box",
              "dotPlot"
            ]
          },
          "x": {
            "type": "string",
            "description": "Result column for the x axis or the categories (a group_by column)."
          },
          "y": {
            "type": "array",
            "maxItems": 8,
            "items": {
              "type": "string"
            },
            "description": "Result columns with the values."
          },
          "series": {
            "type": "string",
            "description": "Result column whose values become separate series."
          },
          "title": {
            "type": "string",
            "maxLength": 200,
            "description": "Write the takeaway, like \"EU revenue doubled in Q3\"."
          },
          "subtitle": {
            "type": "string",
            "maxLength": 300
          },
          "source": {
            "type": "string",
            "maxLength": 200
          },
          "note": {
            "type": "string",
            "maxLength": 300
          },
          "format": {
            "type": "string",
            "enum": [
              "number",
              "percent",
              "currency",
              "compact"
            ]
          },
          "currency": {
            "type": "string",
            "minLength": 3,
            "maxLength": 3
          },
          "highlight": {
            "type": "array",
            "maxItems": 8,
            "items": {
              "type": "string"
            },
            "description": "Series or categories to highlight; the rest are drawn in grey."
          },
          "grain": {
            "type": "string",
            "enum": [
              "day",
              "week",
              "month",
              "quarter",
              "year"
            ],
            "description": "Groups the dates of a time chart by period, and the query's date group columns with them."
          },
          "mode": {
            "type": "string",
            "enum": [
              "stacked",
              "grouped",
              "percent"
            ],
            "description": "columns and bar: stacked (default), side by side, or each adding up to 100%."
          },
          "pie": {
            "type": "boolean",
            "description": "donut: draw a full pie."
          },
          "invert": {
            "type": "boolean",
            "description": "Lower is better for the values drawn (costs). Definitions marked lower is better set it for their own columns."
          },
          "words": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Replace the words a chart draws by itself, e.g. { \"plan\": \"Budget\", \"other\": \"Autres\" }."
          },
          "theme": {
            "type": "string",
            "enum": [
              "datatomcp-dark",
              "datatomcp-light",
              "editorial-light",
              "editorial-dark",
              "brand-light",
              "brand-dark"
            ]
          },
          "width": {
            "type": "integer",
            "minimum": 240,
            "maximum": 2000
          },
          "output": {
            "type": "string",
            "enum": [
              "svg",
              "figure",
              "spec",
              "csv"
            ],
            "description": "Leave out for JSON with spec, svg and meta."
          }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "detail": {}
            }
          }
        }
      }
    }
  }
}