{
  "openapi": "3.1.0",
  "info": {
    "title": "Dock REST API",
    "version": "1.0.1",
    "description": "Dock's REST API. Bearer auth on every endpoint (except auth magic-link send). Returns JSON. Every mutation emits an event that streams over SSE and delivers to org-scoped webhooks.",
    "contact": {
      "name": "Dock Support",
      "url": "https://trydock.ai/docs/support/contact"
    }
  },
  "servers": [
    {
      "url": "https://trydock.ai"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "API key (dk_live_…) or OAuth access token (oat_…)"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "description": "Machine-readable error code. See /docs/api/errors for the catalog.",
            "example": "forbidden"
          },
          "message": {
            "type": "string",
            "description": "Human-readable explanation.",
            "example": "You don't have access to this workspace."
          }
        },
        "required": [
          "code",
          "message"
        ]
      },
      "Workspace": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "ws_01J5Z6Q7…"
          },
          "slug": {
            "type": "string",
            "example": "launch-plan"
          },
          "name": {
            "type": "string",
            "example": "Launch plan"
          },
          "mode": {
            "type": "string",
            "enum": [
              "table",
              "doc"
            ],
            "description": "Default-view hint (which tab opens first). A workspace can hold any combination of table + doc surfaces regardless of mode."
          },
          "visibility": {
            "type": "string",
            "enum": [
              "private",
              "org",
              "unlisted",
              "public"
            ],
            "description": "Who can see and edit. `private` = explicit members only. `org` = every org member is virtual editor. `unlisted` = anyone with the URL can read. `public` = indexed by search."
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "archivedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "pinnedAt": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time",
            "description": "When the calling principal pinned the workspace; null if not pinned by them. Pin is per-user, not org-wide."
          },
          "role": {
            "type": "string",
            "enum": [
              "owner",
              "editor",
              "commenter",
              "viewer"
            ],
            "description": "The calling principal's effective role."
          },
          "createdBy": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Principal"
              },
              {
                "type": [
                  "object",
                  "null"
                ],
                "description": "Null on legacy rows from before attribution shipped."
              }
            ]
          },
          "org": {
            "type": "object",
            "properties": {
              "slug": {
                "type": "string"
              }
            },
            "required": [
              "slug"
            ]
          },
          "primarySurface": {
            "$ref": "#/components/schemas/Surface"
          }
        },
        "required": [
          "id",
          "slug",
          "name",
          "mode",
          "visibility",
          "createdAt",
          "archivedAt",
          "pinnedAt",
          "role",
          "createdBy",
          "org"
        ]
      },
      "ColumnDef": {
        "type": "object",
        "required": [
          "key",
          "label",
          "type",
          "position"
        ],
        "properties": {
          "key": {
            "type": "string",
            "maxLength": 64
          },
          "label": {
            "type": "string",
            "maxLength": 200
          },
          "type": {
            "type": "string",
            "enum": [
              "text",
              "longtext",
              "number",
              "status",
              "person",
              "date",
              "url",
              "checkbox",
              "select"
            ]
          },
          "position": {
            "type": "integer",
            "minimum": 0
          },
          "width": {
            "type": "integer"
          },
          "hidden": {
            "type": "boolean"
          },
          "description": {
            "type": "string",
            "maxLength": 280
          },
          "options": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "value": {
                  "type": "string"
                },
                "label": {
                  "type": "string"
                },
                "color": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "Row": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "workspaceId": {
            "type": "string"
          },
          "position": {
            "type": "integer"
          },
          "data": {
            "type": "object",
            "additionalProperties": true
          },
          "createdByPrincipalId": {
            "type": "string"
          },
          "updatedByPrincipalId": {
            "type": "string",
            "nullable": true
          },
          "createdAt": {
            "type": "string",
            "format": "date-time"
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "BillingSummary": {
        "type": "object",
        "properties": {
          "plan": {
            "type": "string",
            "enum": [
              "free",
              "pro",
              "scale"
            ]
          },
          "monthlyPriceCents": {
            "type": "integer"
          },
          "activeAgents": {
            "type": "integer"
          },
          "agentCap": {
            "type": "integer"
          },
          "activeMembers": {
            "type": "integer"
          },
          "memberCap": {
            "type": "integer"
          },
          "activeWorkspaces": {
            "type": "integer"
          },
          "workspaceCap": {
            "type": "integer"
          },
          "totalRows": {
            "type": "integer"
          },
          "rowsPerWorkspaceCap": {
            "type": "integer"
          },
          "apiCallsPerMonthCap": {
            "type": "integer"
          },
          "webhooksPerMonthCap": {
            "type": "integer"
          },
          "monthlyTotalCents": {
            "type": "integer"
          }
        }
      },
      "Surface": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "srf_01J5Z…"
          },
          "slug": {
            "type": "string",
            "example": "table"
          },
          "kind": {
            "type": "string",
            "enum": [
              "table",
              "doc"
            ]
          }
        },
        "required": [
          "id",
          "slug",
          "kind"
        ]
      },
      "Principal": {
        "type": "object",
        "properties": {
          "principalType": {
            "type": "string",
            "enum": [
              "user",
              "agent"
            ],
            "description": "Whether the actor is a human user or a Dock-managed agent."
          },
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "avatarUrl": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "principalType",
          "id",
          "name",
          "avatarUrl"
        ]
      }
    }
  },
  "paths": {
    "/api/auth": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Send magic-link email",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "email"
                ],
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK. Magic link sent, or { waitlisted: true }.",
            "content": {
              "application/json": {}
            }
          },
          "429": {
            "description": "Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/me": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "Current user + org",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          },
          "401": {
            "description": "Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Auth"
        ],
        "summary": "Update profile (name, avatarUrl)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "avatarUrl": {
                    "type": "string",
                    "format": "uri",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/me/sessions": {
      "delete": {
        "tags": [
          "Auth"
        ],
        "summary": "Sign out everywhere",
        "responses": {
          "200": {
            "description": "OK. Returns { revokedSessions: number }.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/me/export": {
      "get": {
        "tags": [
          "Auth"
        ],
        "summary": "GDPR data export",
        "responses": {
          "200": {
            "description": "JSON bundle.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/columns": {
      "get": {
        "summary": "List a workspace's column schema",
        "description": "Returns every column on the workspace's primary table surface, in display order. Use this before `create_row` / `update_row` so an agent knows which keys are valid. Empty array on doc-only workspaces (columns auto-seed on first row write).",
        "tags": [
          "Columns"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Column list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 64
                          },
                          "label": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 200
                          },
                          "type": {
                            "type": "string",
                            "enum": [
                              "text",
                              "longtext",
                              "number",
                              "status",
                              "person",
                              "date",
                              "url",
                              "checkbox",
                              "select"
                            ]
                          },
                          "position": {
                            "type": "integer",
                            "minimum": 0
                          },
                          "width": {
                            "type": "integer",
                            "exclusiveMinimum": 0
                          },
                          "hidden": {
                            "type": "boolean"
                          },
                          "description": {
                            "type": "string",
                            "maxLength": 280
                          },
                          "options": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "value": {
                                  "type": "string",
                                  "minLength": 1
                                },
                                "label": {
                                  "type": "string",
                                  "minLength": 1
                                },
                                "color": {
                                  "type": "string"
                                }
                              },
                              "required": [
                                "value",
                                "label"
                              ]
                            }
                          }
                        },
                        "required": [
                          "key",
                          "label",
                          "type",
                          "position"
                        ],
                        "additionalProperties": {}
                      }
                    }
                  },
                  "required": [
                    "columns"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Caller has no read access to this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Replace the full column schema",
        "description": "Idempotent full-array replacement. Editor role required. Position values must be contiguous from 0. Renaming a column key triggers comment-anchor migration so existing comments on the old key keep resolving. Use POST instead when only appending one column.",
        "tags": [
          "Columns"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "columns": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 64
                        },
                        "label": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "type": {
                          "type": "string",
                          "enum": [
                            "text",
                            "longtext",
                            "number",
                            "status",
                            "person",
                            "date",
                            "url",
                            "checkbox",
                            "select"
                          ]
                        },
                        "position": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "width": {
                          "type": "integer",
                          "exclusiveMinimum": 0
                        },
                        "hidden": {
                          "type": "boolean"
                        },
                        "description": {
                          "type": "string",
                          "maxLength": 280
                        },
                        "options": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "value": {
                                "type": "string",
                                "minLength": 1
                              },
                              "label": {
                                "type": "string",
                                "minLength": 1
                              },
                              "color": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "value",
                              "label"
                            ]
                          }
                        }
                      },
                      "required": [
                        "key",
                        "label",
                        "type",
                        "position"
                      ],
                      "additionalProperties": {}
                    }
                  }
                },
                "required": [
                  "columns"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replaced.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 64
                          },
                          "label": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 200
                          },
                          "type": {
                            "type": "string",
                            "enum": [
                              "text",
                              "longtext",
                              "number",
                              "status",
                              "person",
                              "date",
                              "url",
                              "checkbox",
                              "select"
                            ]
                          },
                          "position": {
                            "type": "integer",
                            "minimum": 0
                          },
                          "width": {
                            "type": "integer",
                            "exclusiveMinimum": 0
                          },
                          "hidden": {
                            "type": "boolean"
                          },
                          "description": {
                            "type": "string",
                            "maxLength": 280
                          },
                          "options": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "value": {
                                  "type": "string",
                                  "minLength": 1
                                },
                                "label": {
                                  "type": "string",
                                  "minLength": 1
                                },
                                "color": {
                                  "type": "string"
                                }
                              },
                              "required": [
                                "value",
                                "label"
                              ]
                            }
                          }
                        },
                        "required": [
                          "key",
                          "label",
                          "type",
                          "position"
                        ],
                        "additionalProperties": {}
                      }
                    }
                  },
                  "required": [
                    "columns"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Body shape failed validation, or position values aren't contiguous.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Read-only role cannot modify columns.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Append a single column",
        "description": "Server auto-positions the new column as next-after-max so the contiguity invariant holds; any `position` in the request body is ignored. 409 if the key already exists. Editor role required.",
        "tags": [
          "Columns"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "column": {
                    "type": "object",
                    "properties": {
                      "key": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 64
                      },
                      "label": {
                        "type": "string",
                        "minLength": 1,
                        "maxLength": 200
                      },
                      "type": {
                        "type": "string",
                        "enum": [
                          "text",
                          "longtext",
                          "number",
                          "status",
                          "person",
                          "date",
                          "url",
                          "checkbox",
                          "select"
                        ]
                      },
                      "position": {
                        "type": "integer",
                        "minimum": 0
                      },
                      "width": {
                        "type": "integer",
                        "exclusiveMinimum": 0
                      },
                      "hidden": {
                        "type": "boolean"
                      },
                      "description": {
                        "type": "string",
                        "maxLength": 280
                      },
                      "options": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "properties": {
                            "value": {
                              "type": "string",
                              "minLength": 1
                            },
                            "label": {
                              "type": "string",
                              "minLength": 1
                            },
                            "color": {
                              "type": "string"
                            }
                          },
                          "required": [
                            "value",
                            "label"
                          ]
                        }
                      }
                    },
                    "required": [
                      "key",
                      "label",
                      "type"
                    ],
                    "additionalProperties": {}
                  }
                },
                "required": [
                  "column"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Appended; returns the new column plus the full updated list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "column": {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 64
                        },
                        "label": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "type": {
                          "type": "string",
                          "enum": [
                            "text",
                            "longtext",
                            "number",
                            "status",
                            "person",
                            "date",
                            "url",
                            "checkbox",
                            "select"
                          ]
                        },
                        "position": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "width": {
                          "type": "integer",
                          "exclusiveMinimum": 0
                        },
                        "hidden": {
                          "type": "boolean"
                        },
                        "description": {
                          "type": "string",
                          "maxLength": 280
                        },
                        "options": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "value": {
                                "type": "string",
                                "minLength": 1
                              },
                              "label": {
                                "type": "string",
                                "minLength": 1
                              },
                              "color": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "value",
                              "label"
                            ]
                          }
                        }
                      },
                      "required": [
                        "key",
                        "label",
                        "type",
                        "position"
                      ],
                      "additionalProperties": {}
                    },
                    "columns": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "key": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 64
                          },
                          "label": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 200
                          },
                          "type": {
                            "type": "string",
                            "enum": [
                              "text",
                              "longtext",
                              "number",
                              "status",
                              "person",
                              "date",
                              "url",
                              "checkbox",
                              "select"
                            ]
                          },
                          "position": {
                            "type": "integer",
                            "minimum": 0
                          },
                          "width": {
                            "type": "integer",
                            "exclusiveMinimum": 0
                          },
                          "hidden": {
                            "type": "boolean"
                          },
                          "description": {
                            "type": "string",
                            "maxLength": 280
                          },
                          "options": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "value": {
                                  "type": "string",
                                  "minLength": 1
                                },
                                "label": {
                                  "type": "string",
                                  "minLength": 1
                                },
                                "color": {
                                  "type": "string"
                                }
                              },
                              "required": [
                                "value",
                                "label"
                              ]
                            }
                          }
                        },
                        "required": [
                          "key",
                          "label",
                          "type",
                          "position"
                        ],
                        "additionalProperties": {}
                      }
                    }
                  },
                  "required": [
                    "column",
                    "columns"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Read-only role cannot modify columns.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "A column with the same key already exists.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/events": {
      "parameters": [
        {
          "in": "path",
          "name": "slug",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          }
        }
      ],
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "Audit log",
        "parameters": [
          {
            "in": "query",
            "name": "limit",
            "schema": {
              "type": "integer",
              "default": 50
            }
          },
          {
            "in": "query",
            "name": "action",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/subscribe": {
      "parameters": [
        {
          "in": "path",
          "name": "slug",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          }
        }
      ],
      "get": {
        "tags": [
          "Events"
        ],
        "summary": "Server-Sent Events stream",
        "responses": {
          "200": {
            "description": "text/event-stream",
            "content": {
              "text/event-stream": {}
            }
          }
        }
      }
    },
    "/api/keys": {
      "get": {
        "tags": [
          "Keys"
        ],
        "summary": "List keys",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          }
        }
      },
      "post": {
        "tags": [
          "Keys"
        ],
        "summary": "Create key (shown once)",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "agentName": {
                    "type": "string"
                  },
                  "workspaceId": {
                    "type": "string"
                  },
                  "name": {
                    "type": "string"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created. `secret` shown once.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/keys/{id}": {
      "parameters": [
        {
          "in": "path",
          "name": "id",
          "required": true,
          "schema": {
            "type": "string"
          }
        }
      ],
      "delete": {
        "tags": [
          "Keys"
        ],
        "summary": "Revoke key",
        "responses": {
          "204": {
            "description": "Revoked."
          }
        }
      }
    },
    "/api/support": {
      "get": {
        "tags": [
          "Support"
        ],
        "summary": "List tickets for your org",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          }
        }
      },
      "post": {
        "tags": [
          "Support"
        ],
        "summary": "File ticket",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "kind",
                  "title",
                  "body"
                ],
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "bug",
                      "feature",
                      "billing",
                      "question",
                      "other"
                    ]
                  },
                  "title": {
                    "type": "string",
                    "minLength": 3,
                    "maxLength": 200
                  },
                  "body": {
                    "type": "string",
                    "minLength": 5,
                    "maxLength": 10000
                  },
                  "context": {
                    "type": "object"
                  },
                  "attachmentUrls": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uri"
                    },
                    "maxItems": 4
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/support/upload": {
      "post": {
        "tags": [
          "Support"
        ],
        "summary": "Upload screenshot (multipart/form-data)",
        "responses": {
          "200": {
            "description": "OK. Returns blob URL.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/referrals/me": {
      "get": {
        "tags": [
          "Referrals"
        ],
        "summary": "Your referral code + progress",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/api/workspaces": {
      "get": {
        "summary": "List workspaces",
        "description": "List every workspace the caller can access. Pass `?archived=1` to list soft-archived workspaces only; the default view excludes them.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "1"
              ],
              "description": "Set to `1` to list archived workspaces only."
            },
            "required": false,
            "description": "Set to `1` to list archived workspaces only.",
            "name": "archived",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspaces": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/Workspace"
                      }
                    }
                  },
                  "required": [
                    "workspaces"
                  ]
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid bearer token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a workspace",
        "description": "Create a new workspace. Returns the created row. The caller becomes its owner. Visibility defaults to the org's default if omitted.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "example": "Launch plan"
                  },
                  "slug": {
                    "type": "string",
                    "description": "URL slug. Auto-derived from `name` if omitted. Must be unique within the org.",
                    "example": "launch-plan"
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "table",
                      "doc"
                    ],
                    "description": "Default `table`. Auto-resolves to `doc` if `initialMarkdown` is set."
                  },
                  "visibility": {
                    "type": "string",
                    "enum": [
                      "private",
                      "org",
                      "unlisted",
                      "public"
                    ],
                    "description": "Inherits the org's default visibility if omitted."
                  },
                  "initialMarkdown": {
                    "type": "string",
                    "description": "Seed the doc body in the same call. Mode auto-resolves to `doc`. Supports CommonMark + GFM + Dock's rich format set (mermaid, math, callouts, cross-refs, embeds)."
                  }
                },
                "required": [
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspace": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  },
                  "required": [
                    "workspace"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Body failed schema validation.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Workspace cap reached for the current plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Slug already exists in the org.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}": {
      "get": {
        "summary": "Get workspace detail",
        "description": "Fetch a workspace by slug, including columns, member count, mode, and visibility.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "example": "launch-plan"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Workspace detail.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspace": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  },
                  "required": [
                    "workspace"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Not a member of this workspace's org or the workspace itself.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Workspace not found (or visibility hides it from the caller).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update a workspace",
        "description": "Rename, change mode, or change visibility. Editor or owner role required.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "visibility": {
                    "type": "string",
                    "enum": [
                      "private",
                      "org",
                      "unlisted",
                      "public"
                    ],
                    "description": "Who can see and edit. `private` = explicit members only. `org` = every org member is virtual editor. `unlisted` = anyone with the URL can read. `public` = indexed by search."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "table",
                      "doc"
                    ],
                    "description": "Default-view hint (which tab opens first). A workspace can hold any combination of table + doc surfaces regardless of mode."
                  }
                },
                "description": "All fields optional. Send only what you want to change."
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspace": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  },
                  "required": [
                    "workspace"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks editor role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Archive a workspace",
        "description": "Soft-archive. Stamps `archivedAt` + `archivedByPrincipalId`. Rows, doc body, members, and event log stay intact for restore via `POST /api/workspaces/{slug}/unarchive`. Editor role required.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Archived.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks editor role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/unarchive": {
      "post": {
        "summary": "Restore an archived workspace",
        "description": "Reverse a soft-archive. Idempotent on workspaces that aren't archived. Emits a `workspace.unarchived` event carrying the previous archive timestamp. Editor role required.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Restored.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspace": {
                      "$ref": "#/components/schemas/Workspace"
                    }
                  },
                  "required": [
                    "workspace"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/pin": {
      "post": {
        "summary": "Pin a workspace",
        "description": "Personal pin. Writes `WorkspaceMember.pinnedAt = now`. The sidebar Pinned section orders by pinnedAt desc. Pin is per-user; one user pinning doesn't pin for the whole org. Requires an actual membership row (org-visibility virtual viewers can't pin).",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Pinned.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "workspaceId": {
                      "type": "string"
                    },
                    "slug": {
                      "type": "string"
                    },
                    "pinnedAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "workspaceId",
                    "slug",
                    "pinnedAt"
                  ]
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Unpin a workspace",
        "description": "Remove the calling principal's pin. Idempotent.",
        "tags": [
          "Workspaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Unpinned.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/surfaces": {
      "get": {
        "summary": "List surfaces in a workspace",
        "description": "Returns every surface (tab) in the workspace, in tab order.",
        "tags": [
          "Surfaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Surface list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "surfaces": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "srf_01J5Z…"
                          },
                          "slug": {
                            "type": "string",
                            "example": "table-2"
                          },
                          "name": {
                            "type": "string",
                            "example": "Backlog"
                          },
                          "kind": {
                            "type": "string",
                            "enum": [
                              "table",
                              "doc"
                            ],
                            "description": "Whether this tab is a typed-row table or a TipTap rich-text doc."
                          },
                          "position": {
                            "type": "integer",
                            "description": "Tab order within the workspace, 0-indexed."
                          },
                          "columns": {
                            "type": [
                              "array",
                              "null"
                            ],
                            "items": {
                              "type": "object",
                              "properties": {
                                "key": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 64
                                },
                                "label": {
                                  "type": "string",
                                  "minLength": 1,
                                  "maxLength": 200
                                },
                                "type": {
                                  "type": "string",
                                  "enum": [
                                    "text",
                                    "longtext",
                                    "number",
                                    "status",
                                    "person",
                                    "date",
                                    "url",
                                    "checkbox",
                                    "select"
                                  ]
                                },
                                "position": {
                                  "type": "integer",
                                  "minimum": 0
                                },
                                "width": {
                                  "type": "integer",
                                  "exclusiveMinimum": 0
                                },
                                "hidden": {
                                  "type": "boolean"
                                },
                                "description": {
                                  "type": "string",
                                  "maxLength": 280
                                },
                                "options": {
                                  "type": "array",
                                  "items": {
                                    "type": "object",
                                    "properties": {
                                      "value": {
                                        "type": "string",
                                        "minLength": 1
                                      },
                                      "label": {
                                        "type": "string",
                                        "minLength": 1
                                      },
                                      "color": {
                                        "type": "string"
                                      }
                                    },
                                    "required": [
                                      "value",
                                      "label"
                                    ]
                                  }
                                }
                              },
                              "required": [
                                "key",
                                "label",
                                "type",
                                "position"
                              ],
                              "additionalProperties": {}
                            },
                            "description": "Column schema for table surfaces. `null` on doc/html surfaces."
                          }
                        },
                        "required": [
                          "id",
                          "slug",
                          "name",
                          "kind",
                          "position"
                        ]
                      }
                    }
                  },
                  "required": [
                    "surfaces"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Caller can't access this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Add a surface (tab)",
        "description": "Append a new surface to the workspace. Editor role required.",
        "tags": [
          "Surfaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "table",
                      "doc"
                    ],
                    "description": "Whether this tab is a typed-row table or a TipTap rich-text doc."
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200,
                    "description": "Display name. Auto-generated if omitted."
                  },
                  "slug": {
                    "type": "string",
                    "description": "URL slug. Auto-derived from name if omitted."
                  },
                  "columns": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 64
                        },
                        "label": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "type": {
                          "type": "string",
                          "enum": [
                            "text",
                            "longtext",
                            "number",
                            "status",
                            "person",
                            "date",
                            "url",
                            "checkbox",
                            "select"
                          ]
                        },
                        "position": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "width": {
                          "type": "integer",
                          "exclusiveMinimum": 0
                        },
                        "hidden": {
                          "type": "boolean"
                        },
                        "description": {
                          "type": "string",
                          "maxLength": 280
                        },
                        "options": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "value": {
                                "type": "string",
                                "minLength": 1
                              },
                              "label": {
                                "type": "string",
                                "minLength": 1
                              },
                              "color": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "value",
                              "label"
                            ]
                          }
                        }
                      },
                      "required": [
                        "key",
                        "label",
                        "type",
                        "position"
                      ],
                      "additionalProperties": {}
                    },
                    "description": "Optional initial columns for `kind: 'table'`. Defaults to Title/Status/Notes when omitted. Ignored on doc surfaces."
                  }
                },
                "required": [
                  "kind"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "surface": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "srf_01J5Z…"
                        },
                        "slug": {
                          "type": "string",
                          "example": "table-2"
                        },
                        "name": {
                          "type": "string",
                          "example": "Backlog"
                        },
                        "kind": {
                          "type": "string",
                          "enum": [
                            "table",
                            "doc"
                          ],
                          "description": "Whether this tab is a typed-row table or a TipTap rich-text doc."
                        },
                        "position": {
                          "type": "integer",
                          "description": "Tab order within the workspace, 0-indexed."
                        },
                        "columns": {
                          "type": [
                            "array",
                            "null"
                          ],
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 64
                              },
                              "label": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 200
                              },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "longtext",
                                  "number",
                                  "status",
                                  "person",
                                  "date",
                                  "url",
                                  "checkbox",
                                  "select"
                                ]
                              },
                              "position": {
                                "type": "integer",
                                "minimum": 0
                              },
                              "width": {
                                "type": "integer",
                                "exclusiveMinimum": 0
                              },
                              "hidden": {
                                "type": "boolean"
                              },
                              "description": {
                                "type": "string",
                                "maxLength": 280
                              },
                              "options": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "value": {
                                      "type": "string",
                                      "minLength": 1
                                    },
                                    "label": {
                                      "type": "string",
                                      "minLength": 1
                                    },
                                    "color": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "value",
                                    "label"
                                  ]
                                }
                              }
                            },
                            "required": [
                              "key",
                              "label",
                              "type",
                              "position"
                            ],
                            "additionalProperties": {}
                          },
                          "description": "Column schema for table surfaces. `null` on doc/html surfaces."
                        }
                      },
                      "required": [
                        "id",
                        "slug",
                        "name",
                        "kind",
                        "position"
                      ]
                    }
                  },
                  "required": [
                    "surface"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks editor role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/surfaces/{surfaceSlug}": {
      "patch": {
        "summary": "Rename, reslug, reorder, OR replace a surface's column schema",
        "description": "Rename, change the URL slug, move a surface within its workspace's tab strip, OR replace the column schema (table surfaces only). Pass any subset of `name`, `slug`, `position`, `columns`. Position uses 0-based indexing and other tabs shift to keep positions contiguous. Column replace fires `surface.columns_updated`; row.data keys not in the new schema are preserved on disk. Editor role required. Slug renames preserve old URLs via the surface alias table.",
        "tags": [
          "Surfaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "surfaceSlug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64,
                    "description": "New display name."
                  },
                  "slug": {
                    "type": "string",
                    "description": "New URL slug. Lowercase kebab-case, 3-64 chars. Must be unique within the workspace; old slug stays redirectable via the surface alias table."
                  },
                  "position": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "Optional reorder. Equivalent to POST /surfaces/{slug}/move when only repositioning."
                  },
                  "columns": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "key": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 64
                        },
                        "label": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "type": {
                          "type": "string",
                          "enum": [
                            "text",
                            "longtext",
                            "number",
                            "status",
                            "person",
                            "date",
                            "url",
                            "checkbox",
                            "select"
                          ]
                        },
                        "position": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "width": {
                          "type": "integer",
                          "exclusiveMinimum": 0
                        },
                        "hidden": {
                          "type": "boolean"
                        },
                        "description": {
                          "type": "string",
                          "maxLength": 280
                        },
                        "options": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "value": {
                                "type": "string",
                                "minLength": 1
                              },
                              "label": {
                                "type": "string",
                                "minLength": 1
                              },
                              "color": {
                                "type": "string"
                              }
                            },
                            "required": [
                              "value",
                              "label"
                            ]
                          }
                        }
                      },
                      "required": [
                        "key",
                        "label",
                        "type",
                        "position"
                      ],
                      "additionalProperties": {}
                    },
                    "description": "Wholesale replacement of the table surface's column schema. Table surfaces only — doc/html surfaces 400 with a table-only error. Each ColumnDef: `{ key, label, type, position, width?, hidden?, description?, options? }`. `type` ∈ text | longtext | url | status | owner | date | number. `options` is required on status/owner. Existing row.data keys not in the new column set are preserved on disk (they just stop rendering until a column with that key is added back). Fires `surface.columns_updated`."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "surface": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "srf_01J5Z…"
                        },
                        "slug": {
                          "type": "string",
                          "example": "table-2"
                        },
                        "name": {
                          "type": "string",
                          "example": "Backlog"
                        },
                        "kind": {
                          "type": "string",
                          "enum": [
                            "table",
                            "doc"
                          ],
                          "description": "Whether this tab is a typed-row table or a TipTap rich-text doc."
                        },
                        "position": {
                          "type": "integer",
                          "description": "Tab order within the workspace, 0-indexed."
                        },
                        "columns": {
                          "type": [
                            "array",
                            "null"
                          ],
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 64
                              },
                              "label": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 200
                              },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "longtext",
                                  "number",
                                  "status",
                                  "person",
                                  "date",
                                  "url",
                                  "checkbox",
                                  "select"
                                ]
                              },
                              "position": {
                                "type": "integer",
                                "minimum": 0
                              },
                              "width": {
                                "type": "integer",
                                "exclusiveMinimum": 0
                              },
                              "hidden": {
                                "type": "boolean"
                              },
                              "description": {
                                "type": "string",
                                "maxLength": 280
                              },
                              "options": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "value": {
                                      "type": "string",
                                      "minLength": 1
                                    },
                                    "label": {
                                      "type": "string",
                                      "minLength": 1
                                    },
                                    "color": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "value",
                                    "label"
                                  ]
                                }
                              }
                            },
                            "required": [
                              "key",
                              "label",
                              "type",
                              "position"
                            ],
                            "additionalProperties": {}
                          },
                          "description": "Column schema for table surfaces. `null` on doc/html surfaces."
                        }
                      },
                      "required": [
                        "id",
                        "slug",
                        "name",
                        "kind",
                        "position"
                      ]
                    }
                  },
                  "required": [
                    "surface"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Caller lacks editor role.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Slug collides with another surface in the workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a surface",
        "description": "Remove a tab. The workspace must keep at least one surface; deleting the last one returns 400.",
        "tags": [
          "Surfaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "surfaceSlug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Workspace would have no surfaces left.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/surfaces/{surfaceSlug}/move": {
      "post": {
        "summary": "Reorder a surface",
        "description": "Change a surface's tab position. Other tabs shift accordingly.",
        "tags": [
          "Surfaces"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "surfaceSlug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "position": {
                    "type": "integer",
                    "minimum": 0,
                    "description": "New 0-indexed tab position. Other tabs shift to accommodate."
                  }
                },
                "required": [
                  "position"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Moved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "surface": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "srf_01J5Z…"
                        },
                        "slug": {
                          "type": "string",
                          "example": "table-2"
                        },
                        "name": {
                          "type": "string",
                          "example": "Backlog"
                        },
                        "kind": {
                          "type": "string",
                          "enum": [
                            "table",
                            "doc"
                          ],
                          "description": "Whether this tab is a typed-row table or a TipTap rich-text doc."
                        },
                        "position": {
                          "type": "integer",
                          "description": "Tab order within the workspace, 0-indexed."
                        },
                        "columns": {
                          "type": [
                            "array",
                            "null"
                          ],
                          "items": {
                            "type": "object",
                            "properties": {
                              "key": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 64
                              },
                              "label": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 200
                              },
                              "type": {
                                "type": "string",
                                "enum": [
                                  "text",
                                  "longtext",
                                  "number",
                                  "status",
                                  "person",
                                  "date",
                                  "url",
                                  "checkbox",
                                  "select"
                                ]
                              },
                              "position": {
                                "type": "integer",
                                "minimum": 0
                              },
                              "width": {
                                "type": "integer",
                                "exclusiveMinimum": 0
                              },
                              "hidden": {
                                "type": "boolean"
                              },
                              "description": {
                                "type": "string",
                                "maxLength": 280
                              },
                              "options": {
                                "type": "array",
                                "items": {
                                  "type": "object",
                                  "properties": {
                                    "value": {
                                      "type": "string",
                                      "minLength": 1
                                    },
                                    "label": {
                                      "type": "string",
                                      "minLength": 1
                                    },
                                    "color": {
                                      "type": "string"
                                    }
                                  },
                                  "required": [
                                    "value",
                                    "label"
                                  ]
                                }
                              }
                            },
                            "required": [
                              "key",
                              "label",
                              "type",
                              "position"
                            ],
                            "additionalProperties": {}
                          },
                          "description": "Column schema for table surfaces. `null` on doc/html surfaces."
                        }
                      },
                      "required": [
                        "id",
                        "slug",
                        "name",
                        "kind",
                        "position"
                      ]
                    }
                  },
                  "required": [
                    "surface"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/rows": {
      "get": {
        "summary": "List rows in a workspace",
        "description": "Returns rows from the workspace's primary table surface unless `?surface=<slug>` is passed. Newest-first by default.",
        "tags": [
          "Rows"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "description": "Surface slug to scope to. Omit for the primary table surface."
            },
            "required": false,
            "description": "Surface slug to scope to. Omit for the primary table surface.",
            "name": "surface",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Page size. Default 50, max 500."
            },
            "required": false,
            "description": "Page size. Default 50, max 500.",
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Offset-based pagination cursor."
            },
            "required": false,
            "description": "Offset-based pagination cursor.",
            "name": "offset",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Row list with total count.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "rows": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "r_01J5Z…"
                          },
                          "surfaceId": {
                            "type": "string"
                          },
                          "position": {
                            "type": "integer"
                          },
                          "data": {
                            "type": "object",
                            "additionalProperties": {},
                            "description": "Cell values keyed by column id. Types match the column schema."
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "createdBy": {
                            "type": "string",
                            "description": "Principal id (user OR agent)."
                          },
                          "updatedBy": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "surfaceId",
                          "position",
                          "data",
                          "createdAt",
                          "updatedAt",
                          "createdBy",
                          "updatedBy"
                        ]
                      }
                    },
                    "total": {
                      "type": "integer"
                    },
                    "limit": {
                      "type": "integer"
                    },
                    "offset": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "rows",
                    "total",
                    "limit",
                    "offset"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a row",
        "description": "Add a new row to a table surface. `data` keys must match column ids on the surface; values are coerced to the column type. Multi-surface workspaces accept `surface` (slug) or `surfaceId` to pick which sheet the row lands on; omit both to fall through to the workspace's primary table surface.",
        "tags": [
          "Rows"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "additionalProperties": {}
                  },
                  "position": {
                    "type": "integer",
                    "minimum": 0
                  },
                  "auto_create_columns": {
                    "type": "boolean"
                  },
                  "surfaceId": {
                    "type": "string",
                    "minLength": 1
                  },
                  "surface": {
                    "type": "string",
                    "minLength": 1
                  },
                  "surface_slug": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "data"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "row": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "r_01J5Z…"
                        },
                        "surfaceId": {
                          "type": "string"
                        },
                        "position": {
                          "type": "integer"
                        },
                        "data": {
                          "type": "object",
                          "additionalProperties": {},
                          "description": "Cell values keyed by column id. Types match the column schema."
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "createdBy": {
                          "type": "string",
                          "description": "Principal id (user OR agent)."
                        },
                        "updatedBy": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "surfaceId",
                        "position",
                        "data",
                        "createdAt",
                        "updatedAt",
                        "createdBy",
                        "updatedBy"
                      ]
                    }
                  },
                  "required": [
                    "row"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid body.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "402": {
            "description": "Row cap reached for the current plan.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/rows/{id}": {
      "get": {
        "summary": "Get a single row",
        "description": "Fetch one row by id, including its current cell values.",
        "tags": [
          "Rows"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Row detail.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "row": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "r_01J5Z…"
                        },
                        "surfaceId": {
                          "type": "string"
                        },
                        "position": {
                          "type": "integer"
                        },
                        "data": {
                          "type": "object",
                          "additionalProperties": {},
                          "description": "Cell values keyed by column id. Types match the column schema."
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "createdBy": {
                          "type": "string",
                          "description": "Principal id (user OR agent)."
                        },
                        "updatedBy": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "surfaceId",
                        "position",
                        "data",
                        "createdAt",
                        "updatedAt",
                        "createdBy",
                        "updatedBy"
                      ]
                    }
                  },
                  "required": [
                    "row"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Row not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Update a row",
        "description": "Patch the `data` field on an existing row. Only the column keys you include get updated; other cells are left alone. Setting `surface` (slug) or `surfaceId` to a different sheet MOVES the row there: position recomputes to the destination's tail (override with `position`) and a `row.moved_surface` event fires. Same-surface is a no-op move.",
        "tags": [
          "Rows"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "data": {
                    "type": "object",
                    "additionalProperties": {}
                  },
                  "position": {
                    "type": "number"
                  },
                  "auto_create_columns": {
                    "type": "boolean"
                  },
                  "surfaceId": {
                    "type": "string",
                    "minLength": 1
                  },
                  "surface": {
                    "type": "string",
                    "minLength": 1
                  },
                  "surface_slug": {
                    "type": "string",
                    "minLength": 1
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "row": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "r_01J5Z…"
                        },
                        "surfaceId": {
                          "type": "string"
                        },
                        "position": {
                          "type": "integer"
                        },
                        "data": {
                          "type": "object",
                          "additionalProperties": {},
                          "description": "Cell values keyed by column id. Types match the column schema."
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "createdBy": {
                          "type": "string",
                          "description": "Principal id (user OR agent)."
                        },
                        "updatedBy": {
                          "type": "string"
                        }
                      },
                      "required": [
                        "id",
                        "surfaceId",
                        "position",
                        "data",
                        "createdAt",
                        "updatedAt",
                        "createdBy",
                        "updatedBy"
                      ]
                    }
                  },
                  "required": [
                    "row"
                  ]
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a row",
        "description": "Permanent. No soft-delete on individual rows.",
        "tags": [
          "Rows"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/rows/bulk": {
      "post": {
        "summary": "Bulk row operations",
        "description": "Atomic create + update + delete in a single request. Up to 500 ops per call. All ops apply in one Prisma transaction so partial-success scenarios don't happen.",
        "tags": [
          "Rows"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "create": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "object",
                          "additionalProperties": {}
                        },
                        "position": {
                          "type": "integer",
                          "minimum": 0
                        },
                        "auto_create_columns": {
                          "type": "boolean"
                        },
                        "surfaceId": {
                          "type": "string",
                          "minLength": 1
                        },
                        "surface": {
                          "type": "string",
                          "minLength": 1
                        },
                        "surface_slug": {
                          "type": "string",
                          "minLength": 1
                        }
                      },
                      "required": [
                        "data"
                      ]
                    }
                  },
                  "patch": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "data": {
                          "type": "object",
                          "additionalProperties": {}
                        }
                      },
                      "required": [
                        "id",
                        "data"
                      ]
                    }
                  },
                  "delete": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Bulk applied.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "created": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "r_01J5Z…"
                          },
                          "surfaceId": {
                            "type": "string"
                          },
                          "position": {
                            "type": "integer"
                          },
                          "data": {
                            "type": "object",
                            "additionalProperties": {},
                            "description": "Cell values keyed by column id. Types match the column schema."
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "createdBy": {
                            "type": "string",
                            "description": "Principal id (user OR agent)."
                          },
                          "updatedBy": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "surfaceId",
                          "position",
                          "data",
                          "createdAt",
                          "updatedAt",
                          "createdBy",
                          "updatedBy"
                        ]
                      }
                    },
                    "patched": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "r_01J5Z…"
                          },
                          "surfaceId": {
                            "type": "string"
                          },
                          "position": {
                            "type": "integer"
                          },
                          "data": {
                            "type": "object",
                            "additionalProperties": {},
                            "description": "Cell values keyed by column id. Types match the column schema."
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "createdBy": {
                            "type": "string",
                            "description": "Principal id (user OR agent)."
                          },
                          "updatedBy": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "surfaceId",
                          "position",
                          "data",
                          "createdAt",
                          "updatedAt",
                          "createdBy",
                          "updatedBy"
                        ]
                      }
                    },
                    "deleted": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/rows/move": {
      "post": {
        "summary": "Move rows to a different surface",
        "description": "Atomic batch move. All rows move to the target surface (specified by `surfaceId` or `surface` slug). Positions are recomputed at the destination tail.",
        "tags": [
          "Rows"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "rowIds": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "minLength": 1
                    },
                    "minItems": 1,
                    "maxItems": 500
                  },
                  "surfaceId": {
                    "type": "string",
                    "minLength": 1
                  },
                  "surface": {
                    "type": "string",
                    "minLength": 1
                  },
                  "surface_slug": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "rowIds"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Moved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "moved": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "moved"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/rows/{id}/history": {
      "get": {
        "summary": "Row change history",
        "description": "Per-cell change history for one row. Returns chronological diffs with author + timestamp.",
        "tags": [
          "Rows"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "History entries.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "history": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "changedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "changedBy": {
                            "type": "string"
                          },
                          "changedByPrincipalType": {
                            "type": "string",
                            "enum": [
                              "user",
                              "agent"
                            ]
                          },
                          "diff": {
                            "type": "object",
                            "additionalProperties": {
                              "type": "object",
                              "properties": {
                                "from": {},
                                "to": {}
                              }
                            },
                            "description": "Per-column diffs. Keys are column ids; values describe the before/after."
                          }
                        },
                        "required": [
                          "changedAt",
                          "changedBy",
                          "changedByPrincipalType",
                          "diff"
                        ]
                      }
                    }
                  },
                  "required": [
                    "history"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/doc": {
      "get": {
        "summary": "Read the doc body",
        "description": "Returns the workspace's doc body as ProseMirror JSON. 403 if the workspace is in table mode.",
        "tags": [
          "Doc body"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "description": "Surface slug for multi-doc workspaces. Omit for the primary doc surface."
            },
            "required": false,
            "description": "Surface slug for multi-doc workspaces. Omit for the primary doc surface.",
            "name": "surface",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "json",
                "markdown",
                "text"
              ],
              "description": "Response shape: `json` (ProseMirror, default) · `markdown` (CommonMark + GFM, useful for LLM context or textual diff) · `text` (plain text, no formatting marks). Overrides `Accept` header."
            },
            "required": false,
            "description": "Response shape: `json` (ProseMirror, default) · `markdown` (CommonMark + GFM, useful for LLM context or textual diff) · `text` (plain text, no formatting marks). Overrides `Accept` header.",
            "name": "format",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Doc body.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "content": {
                      "description": "ProseMirror JSON. Returned when `?format` is omitted or `?format=json`."
                    },
                    "markdown": {
                      "type": "string",
                      "description": "CommonMark + GFM. Returned when `?format=markdown` (or `Accept: text/markdown` with no `?format`)."
                    },
                    "text": {
                      "type": "string",
                      "description": "Plain text, formatting marks stripped. Returned when `?format=text` (or `Accept: text/plain` with no `?format`)."
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedBy": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "updatedAt",
                    "updatedBy"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Workspace is in table mode (no doc surface).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Replace the doc body",
        "description": "Send either `content` (ProseMirror JSON) or `markdown` (string). When both are present, `content` wins. Markdown gets converted server-side via remark + remark-gfm + Dock's rich format set (mermaid, math, callouts, cross-refs, embeds).",
        "tags": [
          "Doc body"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "content": {},
                  "markdown": {
                    "type": "string",
                    "maxLength": 500000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replaced.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "content": {
                      "description": "ProseMirror JSON. Returned when `?format` is omitted or `?format=json`."
                    },
                    "markdown": {
                      "type": "string",
                      "description": "CommonMark + GFM. Returned when `?format=markdown` (or `Accept: text/markdown` with no `?format`)."
                    },
                    "text": {
                      "type": "string",
                      "description": "Plain text, formatting marks stripped. Returned when `?format=text` (or `Accept: text/plain` with no `?format`)."
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedBy": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "updatedAt",
                    "updatedBy"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Body shape failed validation, OR doc body exceeded byte/depth/node-count cap.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/doc/sections": {
      "post": {
        "summary": "Append a markdown section to the doc",
        "description": "Append-only counterpart to PUT /doc. Saves the round-trip cost of fetch+merge+PUT for agents producing content in chunks (changelog updates, daily standups, ingest pipelines).",
        "tags": [
          "Doc body"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "markdown": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500000
                  }
                },
                "required": [
                  "markdown"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Appended.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "content": {
                      "description": "ProseMirror JSON. Returned when `?format` is omitted or `?format=json`."
                    },
                    "markdown": {
                      "type": "string",
                      "description": "CommonMark + GFM. Returned when `?format=markdown` (or `Accept: text/markdown` with no `?format`)."
                    },
                    "text": {
                      "type": "string",
                      "description": "Plain text, formatting marks stripped. Returned when `?format=text` (or `Accept: text/plain` with no `?format`)."
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedBy": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "updatedAt",
                    "updatedBy"
                  ]
                }
              }
            }
          }
        }
      },
      "patch": {
        "summary": "Replace a single section by heading",
        "description": "Targeted-edit counterpart to PUT /doc (full replacement) and POST /doc/sections (append). Finds the FIRST heading whose plain text matches `heading` (case-sensitive, trimmed), then replaces everything from that heading up to the next heading at the same or shallower level. `markdown` is the FULL replacement INCLUDING the heading line; pass an empty string to delete the section. Returns 404 when no matching heading exists, by design, so a misremembered heading fails loudly. Same byte/depth/node-count guard as PUT /doc; same writeDocBody attribution path.",
        "tags": [
          "Doc body"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "heading": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500
                  },
                  "markdown": {
                    "type": "string",
                    "maxLength": 500000
                  },
                  "allowBlockLoss": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "heading",
                  "markdown"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Replaced.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "content": {
                      "description": "ProseMirror JSON. Returned when `?format` is omitted or `?format=json`."
                    },
                    "markdown": {
                      "type": "string",
                      "description": "CommonMark + GFM. Returned when `?format=markdown` (or `Accept: text/markdown` with no `?format`)."
                    },
                    "text": {
                      "type": "string",
                      "description": "Plain text, formatting marks stripped. Returned when `?format=text` (or `Accept: text/plain` with no `?format`)."
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedBy": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "updatedAt",
                    "updatedBy"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Body shape failed validation, OR doc body exceeded byte/depth/node-count cap after the section was substituted.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "No heading on the doc matches `heading` exactly.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/html": {
      "get": {
        "summary": "Read an HTML surface body",
        "description": "Returns the resolved html surface's body (html, css, js). Empty fields when the surface exists but no body has been written yet. 404 when `?surface_slug=` doesn't match a live html surface.",
        "tags": [
          "HTML body"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "description": "Surface slug for multi-html workspaces. Omit for the primary html surface (lowest position)."
            },
            "required": false,
            "description": "Surface slug for multi-html workspaces. Omit for the primary html surface (lowest position).",
            "name": "surface_slug",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Legacy alias for `surface_slug`. Same semantics. Prefer `surface_slug` in new code."
            },
            "required": false,
            "description": "Legacy alias for `surface_slug`. Same semantics. Prefer `surface_slug` in new code.",
            "name": "surface",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved html body.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "html": {
                      "type": "string",
                      "description": "Sanitized HTML body. Empty string when the surface exists but no body has been written yet."
                    },
                    "css": {
                      "type": "string",
                      "description": "CSS source. Applied inside the sandboxed iframe."
                    },
                    "js": {
                      "type": "string",
                      "description": "JS source. Stored but NOT executed at v1 — the sandbox iframe is scripts-off. Interactive mode lands in a later PR."
                    },
                    "updatedAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "updatedBy": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "updatedByPrincipalType": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "surfaceSlug": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Slug of the resolved html surface. Null when the workspace has no html surface yet."
                    }
                  },
                  "required": [
                    "html",
                    "css",
                    "js",
                    "updatedAt",
                    "updatedBy",
                    "updatedByPrincipalType",
                    "surfaceSlug"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "`surface_slug` didn't match any live html surface in this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "summary": "Replace fields on an HTML surface body",
        "description": "Partial-update friendly. Any of `html` / `css` / `js` can be omitted to leave the column unchanged; pass empty string to clear. HTML is sanitized at write time (see UpdateHtmlSchema). Emits `html.created` on first write to a surface, `html.updated` on subsequent writes — both carry per-field byte counts so webhooks can fan out a meaningful signal. Requires editor role.",
        "tags": [
          "HTML body"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "surface_slug": {
                    "type": "string",
                    "description": "Optional html surface slug. Omit to write to the primary html surface (lowest position)."
                  },
                  "html": {
                    "type": "string",
                    "description": "Sanitized at write time. Caps: 50 KB per field. Omit to leave the column unchanged; pass empty string to clear. Sanitizer strips <script>, every on* event handler, javascript:/vbscript:/file:/data:text/html URIs, <iframe>, <object>, <embed>, <foreignobject>, <meta>, <base>, <link>, formaction smuggling. Allows inline <style>, ARIA attrs, form markup (rendered but inert), data:image/* URIs."
                  },
                  "css": {
                    "type": "string",
                    "description": "CSS source. Cap: 100 KB. Stored verbatim. Omit to leave unchanged; pass empty string to clear."
                  },
                  "js": {
                    "type": "string",
                    "description": "JS source. Cap: 100 KB. Stored but not executed at v1."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Written.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "html": {
                      "type": "string",
                      "description": "Sanitized HTML body. Empty string when the surface exists but no body has been written yet."
                    },
                    "css": {
                      "type": "string",
                      "description": "CSS source. Applied inside the sandboxed iframe."
                    },
                    "js": {
                      "type": "string",
                      "description": "JS source. Stored but NOT executed at v1 — the sandbox iframe is scripts-off. Interactive mode lands in a later PR."
                    },
                    "updatedAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "updatedBy": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "updatedByPrincipalType": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "surfaceSlug": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Slug of the resolved html surface. Null when the workspace has no html surface yet."
                    }
                  },
                  "required": [
                    "html",
                    "css",
                    "js",
                    "updatedAt",
                    "updatedBy",
                    "updatedByPrincipalType",
                    "surfaceSlug"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Body shape failed validation, OR a field exceeded its byte cap (html 50KB, css 100KB, js 100KB, total envelope 250KB), OR sanitizer rejected the html field entirely.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "`surface_slug` didn't match any live html surface, or the workspace has no html surface yet.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/comments": {
      "get": {
        "summary": "List comments on a workspace",
        "description": "Returns comments on this workspace, scoped + filtered by query params. Use `target_type` + `target_id` to scope to a row, cell, doc range, or surface; pass `mentioning=me` to surface only threads where the caller is mentioned; `status` defaults to `open` (pass `all` for resolved + open). Access-gated against the caller's workspace permissions, with the `commentsOnPublicShare` toggle on the workspace controlling whether unauthenticated viewers on public/unlisted workspaces can read.",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "row",
                "cell",
                "doc_range",
                "html_element",
                "surface",
                "workspace",
                "file"
              ]
            },
            "required": false,
            "name": "target_type",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "target_id",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "surface",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "open",
                "resolved",
                "all"
              ],
              "default": "open"
            },
            "required": false,
            "name": "status",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "me"
              ]
            },
            "required": false,
            "name": "mentioning",
            "in": "query"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": false,
            "name": "author",
            "in": "query"
          },
          {
            "schema": {
              "type": "integer",
              "exclusiveMinimum": 0,
              "maximum": 200,
              "default": 50
            },
            "required": false,
            "name": "limit",
            "in": "query"
          },
          {
            "schema": {
              "type": [
                "integer",
                "null"
              ],
              "minimum": 0,
              "default": 0
            },
            "required": false,
            "name": "offset",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Comment list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comments": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "cmt_01J5Z…"
                          },
                          "body": {
                            "type": "string"
                          },
                          "authorId": {
                            "type": "string"
                          },
                          "authorPrincipalType": {
                            "type": "string",
                            "enum": [
                              "user",
                              "agent"
                            ]
                          },
                          "parentId": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "resolvedAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "reactions": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "emoji": {
                                  "type": "string"
                                },
                                "count": {
                                  "type": "integer"
                                },
                                "by": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  },
                                  "description": "Principal ids who reacted."
                                }
                              },
                              "required": [
                                "emoji",
                                "count",
                                "by"
                              ]
                            }
                          }
                        },
                        "required": [
                          "id",
                          "body",
                          "authorId",
                          "authorPrincipalType",
                          "parentId",
                          "resolvedAt",
                          "createdAt",
                          "updatedAt"
                        ]
                      }
                    },
                    "total": {
                      "type": "integer"
                    }
                  },
                  "required": [
                    "comments",
                    "total"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Caller has no read access to this workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a comment (universal)",
        "description": "Create a comment anchored to a doc range, table cell, row, or whole workspace. The `target` discriminated union picks the anchor type.",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "target": {
                    "oneOf": [
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "row"
                            ]
                          },
                          "rowId": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "type",
                          "rowId"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "cell"
                            ]
                          },
                          "rowId": {
                            "type": "string",
                            "minLength": 1
                          },
                          "columnKey": {
                            "type": "string",
                            "minLength": 1,
                            "maxLength": 64
                          }
                        },
                        "required": [
                          "type",
                          "rowId",
                          "columnKey"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "doc_range"
                            ]
                          },
                          "surfaceSlug": {
                            "type": "string",
                            "minLength": 1
                          },
                          "anchor": {
                            "type": "object",
                            "properties": {
                              "from": {
                                "type": "integer",
                                "minimum": 0
                              },
                              "to": {
                                "type": "integer",
                                "exclusiveMinimum": 0
                              },
                              "text": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 600
                              }
                            },
                            "required": [
                              "from",
                              "to",
                              "text"
                            ]
                          }
                        },
                        "required": [
                          "type",
                          "surfaceSlug",
                          "anchor"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "html_element"
                            ]
                          },
                          "surfaceSlug": {
                            "type": "string",
                            "minLength": 1
                          },
                          "anchor": {
                            "type": "object",
                            "properties": {
                              "selector": {
                                "type": "string",
                                "minLength": 1,
                                "maxLength": 2000
                              },
                              "text": {
                                "type": "string",
                                "maxLength": 200
                              }
                            },
                            "required": [
                              "selector"
                            ]
                          }
                        },
                        "required": [
                          "type",
                          "surfaceSlug",
                          "anchor"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "surface"
                            ]
                          },
                          "surfaceSlug": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "type",
                          "surfaceSlug"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "workspace"
                            ]
                          }
                        },
                        "required": [
                          "type"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "file"
                            ]
                          },
                          "fileId": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "type",
                          "fileId"
                        ]
                      }
                    ]
                  },
                  "body": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 10000
                  },
                  "parentId": {
                    "type": "string"
                  },
                  "mentions": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "kind": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ]
                        },
                        "id": {
                          "type": "string",
                          "minLength": 1
                        },
                        "label": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 120
                        }
                      },
                      "required": [
                        "kind",
                        "id",
                        "label"
                      ]
                    },
                    "maxItems": 20
                  },
                  "correlationId": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 64
                  }
                },
                "required": [
                  "target",
                  "body"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comment": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "cmt_01J5Z…"
                        },
                        "body": {
                          "type": "string"
                        },
                        "authorId": {
                          "type": "string"
                        },
                        "authorPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ]
                        },
                        "parentId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "resolvedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reactions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "emoji": {
                                "type": "string"
                              },
                              "count": {
                                "type": "integer"
                              },
                              "by": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Principal ids who reacted."
                              }
                            },
                            "required": [
                              "emoji",
                              "count",
                              "by"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "body",
                        "authorId",
                        "authorPrincipalType",
                        "parentId",
                        "resolvedAt",
                        "createdAt",
                        "updatedAt"
                      ]
                    }
                  },
                  "required": [
                    "comment"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/rows/{id}/comments": {
      "get": {
        "summary": "List comments on a row (legacy)",
        "description": "Legacy row-scoped reader. Kept for back-compat with API clients that followed the older docs at `/docs/api/overview`. New clients should use `GET /api/workspaces/{slug}/comments?target_type=row&target_id=…` which carries the full v1 shape (reactions, resolvedAt, surfaceSlug, mentions in canonical form).",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Comment list, oldest-first.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comments": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "cmt_01J5Z…"
                          },
                          "body": {
                            "type": "string"
                          },
                          "authorId": {
                            "type": "string"
                          },
                          "authorPrincipalType": {
                            "type": "string",
                            "enum": [
                              "user",
                              "agent"
                            ]
                          },
                          "parentId": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "resolvedAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "reactions": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "emoji": {
                                  "type": "string"
                                },
                                "count": {
                                  "type": "integer"
                                },
                                "by": {
                                  "type": "array",
                                  "items": {
                                    "type": "string"
                                  },
                                  "description": "Principal ids who reacted."
                                }
                              },
                              "required": [
                                "emoji",
                                "count",
                                "by"
                              ]
                            }
                          }
                        },
                        "required": [
                          "id",
                          "body",
                          "authorId",
                          "authorPrincipalType",
                          "parentId",
                          "resolvedAt",
                          "createdAt",
                          "updatedAt"
                        ]
                      }
                    }
                  },
                  "required": [
                    "comments"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a comment on a row (legacy)",
        "description": "Legacy row-only comment endpoint. New clients should use the universal endpoint above with `target: { kind: \"row\", rowId }`.",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "body": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 10000
                  },
                  "parentId": {
                    "type": "string"
                  },
                  "mentions": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  }
                },
                "required": [
                  "body"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comment": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "cmt_01J5Z…"
                        },
                        "body": {
                          "type": "string"
                        },
                        "authorId": {
                          "type": "string"
                        },
                        "authorPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ]
                        },
                        "parentId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "resolvedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reactions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "emoji": {
                                "type": "string"
                              },
                              "count": {
                                "type": "integer"
                              },
                              "by": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Principal ids who reacted."
                              }
                            },
                            "required": [
                              "emoji",
                              "count",
                              "by"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "body",
                        "authorId",
                        "authorPrincipalType",
                        "parentId",
                        "resolvedAt",
                        "createdAt",
                        "updatedAt"
                      ]
                    }
                  },
                  "required": [
                    "comment"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/comments/{id}": {
      "get": {
        "summary": "Get a single comment",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Comment detail.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comment": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "cmt_01J5Z…"
                        },
                        "body": {
                          "type": "string"
                        },
                        "authorId": {
                          "type": "string"
                        },
                        "authorPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ]
                        },
                        "parentId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "resolvedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reactions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "emoji": {
                                "type": "string"
                              },
                              "count": {
                                "type": "integer"
                              },
                              "by": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Principal ids who reacted."
                              }
                            },
                            "required": [
                              "emoji",
                              "count",
                              "by"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "body",
                        "authorId",
                        "authorPrincipalType",
                        "parentId",
                        "resolvedAt",
                        "createdAt",
                        "updatedAt"
                      ]
                    }
                  },
                  "required": [
                    "comment"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a comment",
        "description": "Author only.",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "403": {
            "description": "Not the author.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/comments/{id}/resolve": {
      "post": {
        "summary": "Resolve a comment thread",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Resolved.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comment": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "cmt_01J5Z…"
                        },
                        "body": {
                          "type": "string"
                        },
                        "authorId": {
                          "type": "string"
                        },
                        "authorPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ]
                        },
                        "parentId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "resolvedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reactions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "emoji": {
                                "type": "string"
                              },
                              "count": {
                                "type": "integer"
                              },
                              "by": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Principal ids who reacted."
                              }
                            },
                            "required": [
                              "emoji",
                              "count",
                              "by"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "body",
                        "authorId",
                        "authorPrincipalType",
                        "parentId",
                        "resolvedAt",
                        "createdAt",
                        "updatedAt"
                      ]
                    }
                  },
                  "required": [
                    "comment"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/comments/{id}/unresolve": {
      "post": {
        "summary": "Re-open a resolved comment",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Re-opened.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comment": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "cmt_01J5Z…"
                        },
                        "body": {
                          "type": "string"
                        },
                        "authorId": {
                          "type": "string"
                        },
                        "authorPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ]
                        },
                        "parentId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "resolvedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reactions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "emoji": {
                                "type": "string"
                              },
                              "count": {
                                "type": "integer"
                              },
                              "by": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Principal ids who reacted."
                              }
                            },
                            "required": [
                              "emoji",
                              "count",
                              "by"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "body",
                        "authorId",
                        "authorPrincipalType",
                        "parentId",
                        "resolvedAt",
                        "createdAt",
                        "updatedAt"
                      ]
                    }
                  },
                  "required": [
                    "comment"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/comments/{id}/reactions": {
      "post": {
        "summary": "Add an emoji reaction",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "emoji": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 20,
                    "example": "👍"
                  }
                },
                "required": [
                  "emoji"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Reacted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comment": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "cmt_01J5Z…"
                        },
                        "body": {
                          "type": "string"
                        },
                        "authorId": {
                          "type": "string"
                        },
                        "authorPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ]
                        },
                        "parentId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "resolvedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reactions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "emoji": {
                                "type": "string"
                              },
                              "count": {
                                "type": "integer"
                              },
                              "by": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Principal ids who reacted."
                              }
                            },
                            "required": [
                              "emoji",
                              "count",
                              "by"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "body",
                        "authorId",
                        "authorPrincipalType",
                        "parentId",
                        "resolvedAt",
                        "createdAt",
                        "updatedAt"
                      ]
                    }
                  },
                  "required": [
                    "comment"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/comments/{id}/reactions/{emoji}": {
      "delete": {
        "summary": "Remove your reaction",
        "tags": [
          "Comments"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          },
          {
            "schema": {
              "type": "string",
              "example": "👍"
            },
            "required": true,
            "name": "emoji",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Reaction removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "comment": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "cmt_01J5Z…"
                        },
                        "body": {
                          "type": "string"
                        },
                        "authorId": {
                          "type": "string"
                        },
                        "authorPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ]
                        },
                        "parentId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "resolvedAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "reactions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "properties": {
                              "emoji": {
                                "type": "string"
                              },
                              "count": {
                                "type": "integer"
                              },
                              "by": {
                                "type": "array",
                                "items": {
                                  "type": "string"
                                },
                                "description": "Principal ids who reacted."
                              }
                            },
                            "required": [
                              "emoji",
                              "count",
                              "by"
                            ]
                          }
                        }
                      },
                      "required": [
                        "id",
                        "body",
                        "authorId",
                        "authorPrincipalType",
                        "parentId",
                        "resolvedAt",
                        "createdAt",
                        "updatedAt"
                      ]
                    }
                  },
                  "required": [
                    "comment"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/members": {
      "get": {
        "summary": "List workspace members + pending invites",
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Members + pending invites.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "members": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "principalType": {
                            "type": "string",
                            "enum": [
                              "user",
                              "agent"
                            ],
                            "description": "Whether the actor is a human user or a Dock-managed agent."
                          },
                          "principalId": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "email": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "avatarUrl": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "role": {
                            "type": "string",
                            "enum": [
                              "owner",
                              "editor",
                              "commenter",
                              "viewer"
                            ],
                            "description": "Workspace role. Inherited cascades from org membership when no explicit row exists."
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "principalType",
                          "principalId",
                          "name",
                          "email",
                          "avatarUrl",
                          "role",
                          "createdAt"
                        ]
                      }
                    },
                    "invites": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "email": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Null for open-link invites; the email is bound at signup time."
                          },
                          "role": {
                            "type": "string",
                            "enum": [
                              "owner",
                              "editor",
                              "commenter",
                              "viewer"
                            ],
                            "description": "Workspace role. Inherited cascades from org membership when no explicit row exists."
                          },
                          "token": {
                            "type": "string",
                            "description": "Public claim URL: /invites/{token}"
                          },
                          "expiresAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "uses": {
                            "type": "integer"
                          },
                          "maxUses": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "acceptedAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "revokedAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "emailError": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "id",
                          "email",
                          "token",
                          "expiresAt",
                          "uses",
                          "maxUses",
                          "acceptedAt",
                          "revokedAt",
                          "emailError"
                        ]
                      }
                    }
                  },
                  "required": [
                    "members",
                    "invites"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/members/{memberId}": {
      "patch": {
        "summary": "Change a member's workspace role",
        "description": "Promote/demote between viewer/commenter/editor/owner. Cascades any agents owned by that user on this workspace.",
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "memberId",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "owner",
                      "editor",
                      "commenter",
                      "viewer"
                    ],
                    "description": "Workspace role. Inherited cascades from org membership when no explicit row exists."
                  }
                },
                "required": [
                  "role"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Role changed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "member": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "principalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ],
                          "description": "Whether the actor is a human user or a Dock-managed agent."
                        },
                        "principalId": {
                          "type": "string"
                        },
                        "name": {
                          "type": "string"
                        },
                        "email": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "avatarUrl": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "role": {
                          "type": "string",
                          "enum": [
                            "owner",
                            "editor",
                            "commenter",
                            "viewer"
                          ],
                          "description": "Workspace role. Inherited cascades from org membership when no explicit row exists."
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      },
                      "required": [
                        "id",
                        "principalType",
                        "principalId",
                        "name",
                        "email",
                        "avatarUrl",
                        "role",
                        "createdAt"
                      ]
                    }
                  },
                  "required": [
                    "member"
                  ]
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Remove a workspace member",
        "description": "Cascades any agents owned by that user on this workspace (atomic transaction).",
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "memberId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/orgs/{slug}/members": {
      "get": {
        "summary": "List org members + pending invites",
        "description": "Includes viewer's own role + user id so callers can render admin-only UI.",
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Members + pending invites.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "members": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "userId": {
                            "type": "string"
                          },
                          "role": {
                            "type": "string",
                            "enum": [
                              "owner",
                              "admin",
                              "member"
                            ],
                            "description": "Org-level role. Determines what cross-workspace permissions a user has."
                          },
                          "email": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "joinedAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "userId",
                          "role",
                          "email",
                          "name",
                          "joinedAt"
                        ]
                      }
                    },
                    "invites": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "email": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Null for open-link invites; the email is bound at signup time."
                          },
                          "role": {
                            "type": "string",
                            "enum": [
                              "owner",
                              "editor",
                              "commenter",
                              "viewer"
                            ],
                            "description": "Workspace role. Inherited cascades from org membership when no explicit row exists."
                          },
                          "token": {
                            "type": "string",
                            "description": "Public claim URL: /invites/{token}"
                          },
                          "expiresAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "uses": {
                            "type": "integer"
                          },
                          "maxUses": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "acceptedAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "revokedAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "emailError": {
                            "type": [
                              "string",
                              "null"
                            ]
                          }
                        },
                        "required": [
                          "id",
                          "email",
                          "token",
                          "expiresAt",
                          "uses",
                          "maxUses",
                          "acceptedAt",
                          "revokedAt",
                          "emailError"
                        ]
                      }
                    },
                    "viewerRole": {
                      "type": "string",
                      "enum": [
                        "owner",
                        "admin",
                        "member"
                      ],
                      "description": "Org-level role. Determines what cross-workspace permissions a user has."
                    },
                    "viewerUserId": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "members",
                    "invites",
                    "viewerRole",
                    "viewerUserId"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/orgs/{slug}/members/{userId}": {
      "patch": {
        "summary": "Change an org member's role",
        "description": "admin/owner only. Owner role is immutable via this endpoint.",
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "userId",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "role": {
                    "type": "string",
                    "enum": [
                      "admin",
                      "member"
                    ]
                  }
                },
                "required": [
                  "role"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Role changed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Remove from org (or self-leave)",
        "description": "admin/owner OR self. Bulk-deletes all WorkspaceMember rows in the org's workspaces + emits `member.removed` per workspace + deletes the OrgMember row. Sole-owner removal is blocked.",
        "tags": [
          "Members"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "userId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Removed.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Sole owner — refusing to remove.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/orgs/{slug}/webhooks": {
      "get": {
        "summary": "List org webhooks",
        "description": "Every webhook configured for the org. Secrets are returned as a preview only.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Webhook list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhooks": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "wh_01J5Z…"
                          },
                          "url": {
                            "type": "string",
                            "format": "uri"
                          },
                          "events": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            },
                            "description": "Event names this webhook subscribes to. See `CreateWebhookSchema` for the canonical list."
                          },
                          "active": {
                            "type": "boolean"
                          },
                          "secretPreview": {
                            "type": "string",
                            "example": "whsec_a1…",
                            "description": "First 8 chars of the signing secret. The full secret is only returned at create + rotate time."
                          },
                          "createdByPrincipalId": {
                            "type": "string"
                          },
                          "createdByPrincipalType": {
                            "type": "string",
                            "enum": [
                              "user",
                              "agent"
                            ],
                            "description": "Whether the actor is a human user or a Dock-managed agent."
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "url",
                          "events",
                          "active",
                          "secretPreview",
                          "createdByPrincipalId",
                          "createdByPrincipalType",
                          "createdAt"
                        ]
                      }
                    }
                  },
                  "required": [
                    "webhooks"
                  ]
                }
              }
            }
          }
        }
      },
      "post": {
        "summary": "Create a webhook",
        "description": "Register a webhook subscription. The full signing secret is returned exactly once in the response — store it before the response is closed.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "maxLength": 2048,
                    "format": "uri"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "enum": [
                        "row.created",
                        "row.updated",
                        "row.deleted",
                        "row.sealed",
                        "comment.added",
                        "comment.deleted",
                        "member.invited",
                        "member.joined",
                        "member.removed",
                        "member.role_changed",
                        "workspace.created",
                        "workspace.renamed",
                        "workspace.columns_updated",
                        "workspace.visibility_changed",
                        "workspace.archived",
                        "doc.created",
                        "doc.updated",
                        "doc.heading_added",
                        "doc.mention_added",
                        "message.sent",
                        "file.uploaded",
                        "file.renamed",
                        "file.moved",
                        "file.archived",
                        "file.restored",
                        "file.version_replaced",
                        "file.starred",
                        "file.tagged",
                        "file.described",
                        "file.shared",
                        "file.share_revoked",
                        "file.commented",
                        "folder.created",
                        "folder.archived"
                      ]
                    },
                    "minItems": 1,
                    "default": [
                      "row.created",
                      "row.updated",
                      "row.deleted"
                    ]
                  }
                },
                "required": [
                  "url"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Created.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "wh_01J5Z…"
                        },
                        "url": {
                          "type": "string",
                          "format": "uri"
                        },
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Event names this webhook subscribes to. See `CreateWebhookSchema` for the canonical list."
                        },
                        "active": {
                          "type": "boolean"
                        },
                        "secretPreview": {
                          "type": "string",
                          "example": "whsec_a1…",
                          "description": "First 8 chars of the signing secret. The full secret is only returned at create + rotate time."
                        },
                        "createdByPrincipalId": {
                          "type": "string"
                        },
                        "createdByPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ],
                          "description": "Whether the actor is a human user or a Dock-managed agent."
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "secret": {
                          "type": "string",
                          "example": "whsec_…",
                          "description": "The full signing secret. Returned ONCE at creation and on rotate-secret. Store it; it cannot be retrieved later."
                        }
                      },
                      "required": [
                        "id",
                        "url",
                        "events",
                        "active",
                        "secretPreview",
                        "createdByPrincipalId",
                        "createdByPrincipalType",
                        "createdAt",
                        "secret"
                      ]
                    }
                  },
                  "required": [
                    "webhook"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "URL failed SSRF guard (loopback, private range, cloud metadata).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/orgs/{slug}/webhooks/{id}": {
      "patch": {
        "summary": "Toggle webhook active state",
        "description": "Enable or disable a webhook without deleting it. Body: `{ active: boolean }`.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "active": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "active"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string"
                        },
                        "url": {
                          "type": "string",
                          "format": "uri"
                        },
                        "active": {
                          "type": "boolean"
                        }
                      },
                      "required": [
                        "id",
                        "url",
                        "active"
                      ]
                    }
                  },
                  "required": [
                    "webhook"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Delete a webhook",
        "description": "Removes the subscription. In-flight deliveries are cancelled.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Deleted.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deleted": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "deleted"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/orgs/{slug}/webhooks/{id}/deliveries": {
      "get": {
        "summary": "List recent webhook deliveries",
        "description": "Up to 50 most recent delivery attempts for one webhook, newest first. Use to debug failed integrations or watch retry status.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Delivery list.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "deliveries": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "event": {
                            "type": "string"
                          },
                          "status": {
                            "type": "string",
                            "enum": [
                              "pending",
                              "delivered",
                              "failed"
                            ]
                          },
                          "attempts": {
                            "type": "integer"
                          },
                          "lastResponseCode": {
                            "type": [
                              "integer",
                              "null"
                            ]
                          },
                          "lastError": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "nextAttemptAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "deliveredAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "event",
                          "status",
                          "attempts",
                          "lastResponseCode",
                          "lastError",
                          "nextAttemptAt",
                          "deliveredAt",
                          "createdAt"
                        ]
                      }
                    }
                  },
                  "required": [
                    "deliveries"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Webhook not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/orgs/{slug}/webhooks/{id}/rotate-secret": {
      "post": {
        "summary": "Rotate webhook signing secret",
        "description": "Generate a fresh signing secret. Returned exactly once. Subsequent deliveries are signed with the new secret only — update your receiver before the next event lands.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "id",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Rotated.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "webhook": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "wh_01J5Z…"
                        },
                        "url": {
                          "type": "string",
                          "format": "uri"
                        },
                        "events": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          },
                          "description": "Event names this webhook subscribes to. See `CreateWebhookSchema` for the canonical list."
                        },
                        "active": {
                          "type": "boolean"
                        },
                        "secretPreview": {
                          "type": "string",
                          "example": "whsec_a1…",
                          "description": "First 8 chars of the signing secret. The full secret is only returned at create + rotate time."
                        },
                        "createdByPrincipalId": {
                          "type": "string"
                        },
                        "createdByPrincipalType": {
                          "type": "string",
                          "enum": [
                            "user",
                            "agent"
                          ],
                          "description": "Whether the actor is a human user or a Dock-managed agent."
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "secret": {
                          "type": "string",
                          "example": "whsec_…",
                          "description": "The full signing secret. Returned ONCE at creation and on rotate-secret. Store it; it cannot be retrieved later."
                        }
                      },
                      "required": [
                        "id",
                        "url",
                        "events",
                        "active",
                        "secretPreview",
                        "createdByPrincipalId",
                        "createdByPrincipalType",
                        "createdAt",
                        "secret"
                      ]
                    }
                  },
                  "required": [
                    "webhook"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing": {
      "get": {
        "summary": "Get billing summary",
        "description": "Current plan, subscription status, agent/member/workspace counts, next-invoice date, card on file. Both users and agents can call.",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Billing summary.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "plan": {
                      "type": "string",
                      "enum": [
                        "free",
                        "pro",
                        "scale"
                      ],
                      "description": "Plan tier. Caps live in `src/lib/plan.ts`."
                    },
                    "status": {
                      "type": "string",
                      "description": "Subscription status from Stripe (`active`, `trialing`, `past_due`, `canceled`, ...) or `none` if no subscription exists."
                    },
                    "cancelAtPeriodEnd": {
                      "type": [
                        "boolean",
                        "null"
                      ],
                      "description": "True when the user has scheduled a downgrade/cancel at the end of the current period."
                    },
                    "currentPeriodEnd": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "agentCount": {
                      "type": "integer"
                    },
                    "memberCount": {
                      "type": "integer"
                    },
                    "workspaceCount": {
                      "type": "integer"
                    },
                    "caps": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "integer"
                      },
                      "description": "Per-tier caps for the active plan."
                    },
                    "card": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "properties": {
                        "brand": {
                          "type": "string"
                        },
                        "last4": {
                          "type": "string"
                        },
                        "expMonth": {
                          "type": "integer"
                        },
                        "expYear": {
                          "type": "integer"
                        }
                      },
                      "required": [
                        "brand",
                        "last4",
                        "expMonth",
                        "expYear"
                      ]
                    },
                    "designPartnerPro": {
                      "type": "boolean",
                      "description": "Design-partner orgs are on Scale at $0."
                    }
                  },
                  "required": [
                    "plan",
                    "status"
                  ],
                  "description": "Open-ended summary. Fields beyond `plan` + `status` may be added over time."
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/checkout": {
      "post": {
        "summary": "Create a Stripe Checkout session",
        "description": "Low-level — returns a Checkout URL for entering a card. Prefer `POST /api/billing/upgrade` in most flows; that handles the plan-switch branches too. Use this when you specifically want a fresh Checkout (e.g. after a portal cancellation). 409s if a subscription already exists.",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "plan": {
                    "type": "string",
                    "enum": [
                      "pro",
                      "scale"
                    ],
                    "description": "Target plan. Defaults to `pro`."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Checkout URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    },
                    "plan": {
                      "type": "string",
                      "enum": [
                        "pro",
                        "scale"
                      ]
                    }
                  },
                  "required": [
                    "url",
                    "plan"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Stripe not configured on this deployment.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Subscription already exists, or org is on design-partner Scale at $0.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/portal": {
      "post": {
        "summary": "Create a Stripe Customer Portal session",
        "description": "Returns a short-lived URL for the Stripe Customer Portal — card changes, invoice history, manual cancellation. The portal itself is browser-only; agents can hand the link back to their user.",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "responses": {
          "200": {
            "description": "Portal URL.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  },
                  "required": [
                    "url"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Stripe not configured.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/upgrade": {
      "post": {
        "summary": "Upgrade plan (Pro or Scale)",
        "description": "Upgrade or switch to a paid plan. **Behavior depends on principal type:**\n\n- **HUMAN** (session cookie): one-call execution. The Settings UI click is itself the consent signal.\n- **AGENT** (DK key, OAuth bearer): consent-gated. First call returns `{ status: \"confirmation_required\", confirm_token, message, expires_in }`. Agent surfaces the message to its user, user confirms, agent re-calls within 60s with the `confirm_token` set. Optionally pass `mode: \"web\"` for a web-approve URL the agent prints in chat — agent then polls `/api/web-approve/status`.\n\n**Fast paths** (both principal types): no existing subscription returns a Checkout URL; same-plan + scheduled-cancel resumes; design-partner orgs no-op at Scale.",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "plan": {
                    "type": "string",
                    "enum": [
                      "pro",
                      "scale"
                    ],
                    "description": "Target plan. Defaults to `pro`."
                  },
                  "confirm_token": {
                    "type": "string",
                    "description": "Required for AGENT-initiated live plan flips. Returned on the first call."
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "chat",
                      "web"
                    ],
                    "description": "Agent-only consent UX. `chat` (default) = handshake via confirm_token. `web` = mint a web-approve URL the user clicks."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Discriminated by `status`: `switched` | `resumed` | `checkout-required` | `confirmation_required` | `web-approve-required` | `design-partner`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "plan": {
                      "type": "string",
                      "enum": [
                        "free",
                        "pro",
                        "scale"
                      ],
                      "description": "Plan tier. Caps live in `src/lib/plan.ts`."
                    },
                    "status": {
                      "type": "string"
                    },
                    "checkoutUrl": {
                      "type": "string",
                      "format": "uri"
                    },
                    "targetPlan": {
                      "type": "string",
                      "enum": [
                        "pro",
                        "scale"
                      ]
                    },
                    "confirm_token": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    },
                    "expires_in": {
                      "type": "integer"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri",
                      "description": "web-approve flow only."
                    }
                  },
                  "required": [
                    "status"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Stripe not configured, or invalid confirm_token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/downgrade": {
      "post": {
        "summary": "Schedule a downgrade to Free",
        "description": "Schedule a downgrade to Free at the end of the current billing period. The org keeps its current plan + caps until then. Idempotent on already-Free orgs.\n\nSame human-vs-agent consent split as `/api/billing/upgrade`: humans execute directly; agents must use the `confirm_token` handshake (or `mode: \"web\"` for the web-approve flow).",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "confirm_token": {
                    "type": "string"
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "chat",
                      "web"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Discriminated by `status`: `downgrade-scheduled` | `already-free` | `confirmation_required` | `web-approve-required`.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "plan": {
                      "type": "string",
                      "enum": [
                        "free",
                        "pro",
                        "scale"
                      ],
                      "description": "Plan tier. Caps live in `src/lib/plan.ts`."
                    },
                    "status": {
                      "type": "string"
                    },
                    "confirm_token": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    },
                    "expires_in": {
                      "type": "integer"
                    },
                    "url": {
                      "type": "string",
                      "format": "uri"
                    }
                  },
                  "required": [
                    "status"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Invalid confirm_token.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/billing/request-limit-increase": {
      "post": {
        "summary": "Request a limit increase",
        "description": "Agentic escape hatch. When the org bumps a cap (agents, workspaces, rows, anything), call this to register demand. We count signals on the admin side; no ticket, no reply loop, no email. Body is optional — at minimum we record \"someone hit a cap\".",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "agents",
                      "workspaces",
                      "rows",
                      "other"
                    ],
                    "description": "Defaults to `other`."
                  },
                  "desiredValue": {
                    "type": "integer",
                    "description": "What the caller would like the cap to be."
                  },
                  "reason": {
                    "type": "string",
                    "maxLength": 500,
                    "description": "Free-text context. Truncated to 500 chars."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Logged.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "status": {
                      "type": "string",
                      "enum": [
                        "received"
                      ]
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "status",
                    "message"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/sheets/functions": {
      "get": {
        "summary": "List the formula function catalog",
        "description": "Returns the 39-function Dock Sheets catalog (12 V1 + 14 V2 + 7 V3 + 6 V4), the alias map (e.g. CONCAT → CONCATENATE), and the category list. Public endpoint, no auth required. Use this before writing a formula carrier so you only reference functions that actually exist.",
        "tags": [
          "Sheets formulas"
        ],
        "parameters": [
          {
            "schema": {
              "type": "string",
              "enum": [
                "Math",
                "Logic",
                "Text",
                "Date",
                "Lookup",
                "Predicates",
                "Other"
              ],
              "description": "Filter to one category."
            },
            "required": false,
            "description": "Filter to one category.",
            "name": "category",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "v1",
                "v2",
                "v3",
                "v4"
              ],
              "description": "Filter to one rollout slice."
            },
            "required": false,
            "description": "Filter to one rollout slice.",
            "name": "slice",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Case-insensitive substring match against name, description, and signature."
            },
            "required": false,
            "description": "Case-insensitive substring match against name, description, and signature.",
            "name": "name",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Filtered catalog.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "count": {
                      "type": "integer"
                    },
                    "functions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": {
                            "type": "string",
                            "example": "SUM"
                          },
                          "signature": {
                            "type": "string",
                            "example": "(range)"
                          },
                          "description": {
                            "type": "string",
                            "example": "Add up the numbers in a range."
                          },
                          "category": {
                            "type": "string",
                            "enum": [
                              "Math",
                              "Logic",
                              "Text",
                              "Date",
                              "Lookup",
                              "Predicates",
                              "Other"
                            ],
                            "example": "Math"
                          },
                          "slice": {
                            "type": "string",
                            "enum": [
                              "v1",
                              "v2",
                              "v3",
                              "v4"
                            ],
                            "example": "v1"
                          },
                          "examples": {
                            "type": "array",
                            "items": {
                              "type": "object",
                              "properties": {
                                "formula": {
                                  "type": "string",
                                  "example": "=SUM(B2:B10)"
                                },
                                "result": {
                                  "type": "string",
                                  "example": "318.42"
                                }
                              },
                              "required": [
                                "formula",
                                "result"
                              ]
                            }
                          }
                        },
                        "required": [
                          "name",
                          "signature",
                          "description",
                          "category",
                          "slice",
                          "examples"
                        ]
                      }
                    },
                    "aliases": {
                      "type": "object",
                      "additionalProperties": {
                        "type": "string"
                      }
                    },
                    "categories": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    }
                  },
                  "required": [
                    "count",
                    "functions",
                    "aliases",
                    "categories"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/sheets/validate-formula": {
      "post": {
        "summary": "Parse-check a formula expression",
        "description": "Returns { ok, error?, referencedFunctions, unknownFunctions }. Catches syntax errors and likely typos before you persist a stale carrier into a row. Public endpoint, no auth, no workspace context required.",
        "tags": [
          "Sheets formulas"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "formula": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4000,
                    "example": "=SUMIF(B2:B10, \">0\")"
                  }
                },
                "required": [
                  "formula"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Validation result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "error": {
                      "type": "string",
                      "description": "Plain-language reason the formula didn't parse, when ok=false."
                    },
                    "referencedFunctions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Canonical function names referenced in the formula. Aliases are resolved to their canonical form."
                    },
                    "unknownFunctions": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      },
                      "description": "Any identifier that looked like a function call but isn't in the Dock catalog. Likely typos or unsupported functions."
                    }
                  },
                  "required": [
                    "ok",
                    "referencedFunctions",
                    "unknownFunctions"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/sheets/evaluate-formula": {
      "post": {
        "summary": "Evaluate a formula expression",
        "description": "Two modes:\n\n- **Standalone** — body `{ formula }` only. Public. Evaluates against an empty grid. Useful for `=SUM(1, 2, 3)` style sanity checks.\n- **In workspace** — body `{ formula, workspaceSlug, at? }`. Loads the workspace's columns + rows, evaluates the formula as if pasted into `at` (or the first cell if omitted), resolves references against actual data. Requires read access to the workspace.\n\nReturns `{ ok, displayValue, error? }`.",
        "tags": [
          "Sheets formulas"
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "formula": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 4000,
                    "example": "=SUM(A1:A3)"
                  },
                  "workspaceSlug": {
                    "type": "string",
                    "description": "Workspace slug. Pass to evaluate against real data; omit for standalone."
                  },
                  "at": {
                    "type": "object",
                    "properties": {
                      "rowId": {
                        "type": "string"
                      },
                      "colKey": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "rowId",
                      "colKey"
                    ],
                    "description": "Optional anchor cell (only used with workspaceSlug)."
                  }
                },
                "required": [
                  "formula"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Evaluation result.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean"
                    },
                    "displayValue": {
                      "type": "string",
                      "description": "The string the UI would render in the cell (matches HyperFormula's display, e.g. '60', '4.20', '#DIV/0!')."
                    },
                    "error": {
                      "type": "object",
                      "properties": {
                        "code": {
                          "type": "string",
                          "example": "DIV_BY_ZERO"
                        },
                        "summary": {
                          "type": "string",
                          "example": "Dividing by zero. Check the cell on the right side of the /."
                        }
                      },
                      "required": [
                        "code",
                        "summary"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "displayValue"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Workspace has no columns, or anchor cell invalid.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "In-workspace mode + unauthenticated + private workspace.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Workspace, row, or column not found.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/files": {
      "get": {
        "summary": "List files (with optional sort, search, starred, recent views)",
        "description": "Returns folders + files in the given Files surface. Default view = current folder's children. Pass `view=starred` for a flat surface-wide starred list, `view=recent` for the 50 most-recently-updated. `q` widens to a surface-wide name-contains search. `sort` + `order` override the default name asc.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "surfaceSlug",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "description": "Folder id to descend into; omit or pass 'null' for root."
            },
            "required": false,
            "description": "Folder id to descend into; omit or pass 'null' for root.",
            "name": "parentFolderId",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "starred",
                "recent"
              ],
              "description": "Override the default folder-scoped listing."
            },
            "required": false,
            "description": "Override the default folder-scoped listing.",
            "name": "view",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "example": "hero"
            },
            "required": false,
            "name": "q",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "name",
                "createdAt",
                "updatedAt",
                "size",
                "mimeType"
              ]
            },
            "required": false,
            "name": "sort",
            "in": "query"
          },
          {
            "schema": {
              "type": "string",
              "enum": [
                "asc",
                "desc"
              ]
            },
            "required": false,
            "name": "order",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Folders + files",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "folders": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          },
                          "parentFolderId": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "position": {
                            "type": "integer"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "parentFolderId",
                          "position",
                          "createdAt",
                          "updatedAt"
                        ]
                      }
                    },
                    "files": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "example": "cmpfile_…"
                          },
                          "name": {
                            "type": "string",
                            "example": "hero.png"
                          },
                          "parentFolderId": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "size": {
                            "type": "integer",
                            "description": "Bytes."
                          },
                          "mimeType": {
                            "type": "string",
                            "example": "image/png"
                          },
                          "thumbUrl": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "description": "Server-generated 256-px webp URL. Null for non-raster files."
                          },
                          "starred": {
                            "type": "boolean"
                          },
                          "starredAt": {
                            "type": [
                              "string",
                              "null"
                            ],
                            "format": "date-time"
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "tags": {
                            "type": "array",
                            "items": {
                              "type": "string"
                            }
                          },
                          "exif": {
                            "type": [
                              "object",
                              "null"
                            ],
                            "additionalProperties": {}
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          },
                          "updatedAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "name",
                          "parentFolderId",
                          "size",
                          "mimeType",
                          "thumbUrl",
                          "createdAt",
                          "updatedAt"
                        ]
                      }
                    }
                  },
                  "required": [
                    "folders",
                    "files"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Files surface not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/files/proxy-upload": {
      "post": {
        "summary": "Upload a file (server-proxied)",
        "description": "Multipart upload that streams bytes through the server. Used for SVG (server-side DOMPurify sanitization) and raster images (EXIF strip + 256-px webp thumb generation). Capped at 25 MB by the serverless body limit. Larger files MUST use the direct-to-blob token route (`POST /api/workspaces/{slug}/files`).",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "surface_slug": {
                    "type": "string"
                  },
                  "parent_folder_id": {
                    "type": "string"
                  },
                  "file": {
                    "format": "binary"
                  }
                },
                "required": [
                  "surface_slug"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "File row",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "example": "cmpfile_…"
                    },
                    "name": {
                      "type": "string",
                      "example": "hero.png"
                    },
                    "parentFolderId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "size": {
                      "type": "integer",
                      "description": "Bytes."
                    },
                    "mimeType": {
                      "type": "string",
                      "example": "image/png"
                    },
                    "thumbUrl": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Server-generated 256-px webp URL. Null for non-raster files."
                    },
                    "starred": {
                      "type": "boolean"
                    },
                    "starredAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "tags": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "exif": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": {}
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "parentFolderId",
                    "size",
                    "mimeType",
                    "thumbUrl",
                    "createdAt",
                    "updatedAt"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Bad MIME / sanitization rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "Over per-file or per-tier storage cap",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/files/{fileId}": {
      "patch": {
        "summary": "Rename, move, or restore a file",
        "description": "Discriminated payload: `{ name }` to rename, `{ parentFolderId }` to move (pass `null` for root, must be in the same surface), `{ restore: true }` to un-archive a soft-deleted file. Rename keeps blobKey stable so deep-links never break. Restore + name in the same body is rejected.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "fileId",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "parentFolderId": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "restore": {
                    "type": "boolean",
                    "enum": [
                      true
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated file",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "example": "cmpfile_…"
                    },
                    "name": {
                      "type": "string",
                      "example": "hero.png"
                    },
                    "parentFolderId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "size": {
                      "type": "integer",
                      "description": "Bytes."
                    },
                    "mimeType": {
                      "type": "string",
                      "example": "image/png"
                    },
                    "thumbUrl": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Server-generated 256-px webp URL. Null for non-raster files."
                    },
                    "starred": {
                      "type": "boolean"
                    },
                    "starredAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "tags": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "exif": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": {}
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "parentFolderId",
                    "size",
                    "mimeType",
                    "thumbUrl",
                    "createdAt",
                    "updatedAt"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Cross-surface move / archived rename / combo rejected",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "File not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Archive (soft-delete) a file",
        "description": "Sets archivedAt + the archivedBy stamp. Blob stays in storage and the org's storage counter stays incremented until the 30-day trash cleanup cron hard-deletes it. Restorable via PATCH `{ restore: true }`.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "fileId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Archived",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "Not found or already archived",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/files/{fileId}/metadata": {
      "patch": {
        "summary": "Update file metadata (starred · description · tags)",
        "description": "Each call accepts any subset of the three keys. Tags are normalised server-side: lowercased, trimmed, de-duplicated, empties dropped. Description capped at 2 000 chars; empty string clears. Max 16 tags × 32 chars each.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "fileId",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "starred": {
                    "type": "boolean"
                  },
                  "description": {
                    "type": [
                      "string",
                      "null"
                    ],
                    "maxLength": 2000
                  },
                  "tags": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "maxLength": 32
                    },
                    "maxItems": 16
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated file",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "file": {
                      "type": "object",
                      "properties": {
                        "id": {
                          "type": "string",
                          "example": "cmpfile_…"
                        },
                        "name": {
                          "type": "string",
                          "example": "hero.png"
                        },
                        "parentFolderId": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "size": {
                          "type": "integer",
                          "description": "Bytes."
                        },
                        "mimeType": {
                          "type": "string",
                          "example": "image/png"
                        },
                        "thumbUrl": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "description": "Server-generated 256-px webp URL. Null for non-raster files."
                        },
                        "starred": {
                          "type": "boolean"
                        },
                        "starredAt": {
                          "type": [
                            "string",
                            "null"
                          ],
                          "format": "date-time"
                        },
                        "description": {
                          "type": [
                            "string",
                            "null"
                          ]
                        },
                        "tags": {
                          "type": "array",
                          "items": {
                            "type": "string"
                          }
                        },
                        "exif": {
                          "type": [
                            "object",
                            "null"
                          ],
                          "additionalProperties": {}
                        },
                        "createdAt": {
                          "type": "string",
                          "format": "date-time"
                        },
                        "updatedAt": {
                          "type": "string",
                          "format": "date-time"
                        }
                      },
                      "required": [
                        "id",
                        "name",
                        "parentFolderId",
                        "size",
                        "mimeType",
                        "thumbUrl",
                        "createdAt",
                        "updatedAt"
                      ]
                    }
                  },
                  "required": [
                    "ok",
                    "file"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "File not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Zod validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/files/{fileId}/share": {
      "post": {
        "summary": "Mint a public share token for a file",
        "description": "Returns a public URL anyone can open (no auth) to view + download the file. Token is 32 random bytes (~256 bits of entropy). Editor role required.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "fileId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Share URL",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "url": {
                      "type": "string",
                      "example": "https://trydock.ai/share/files/abc…"
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "id",
                    "url",
                    "createdAt"
                  ]
                }
              }
            }
          },
          "404": {
            "description": "File not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "summary": "List active share tokens for a file",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "fileId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Tokens list",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tokens": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "url": {
                            "type": "string",
                            "example": "https://trydock.ai/share/files/abc…"
                          },
                          "createdAt": {
                            "type": "string",
                            "format": "date-time"
                          }
                        },
                        "required": [
                          "id",
                          "url",
                          "createdAt"
                        ]
                      }
                    }
                  },
                  "required": [
                    "tokens"
                  ]
                }
              }
            }
          }
        }
      },
      "delete": {
        "summary": "Revoke a share token",
        "description": "Soft-revoke (sets revokedAt). Idempotent: second revoke returns `alreadyRevoked: true`.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "fileId",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "tokenId",
            "in": "query"
          }
        ],
        "responses": {
          "200": {
            "description": "Revoked or already-revoked",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "enum": [
                        true
                      ]
                    },
                    "alreadyRevoked": {
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "ok"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "Missing tokenId",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/files/{fileId}/versions": {
      "post": {
        "summary": "Replace file bytes (keep id, comments, share links)",
        "description": "Same file id, same comments + share tokens + deep-link URL; new blobKey + new sha256 under the hood. The new bytes must be in the same MIME category as the previous version (image → image, video → video, etc.); cross-category swaps reject 400.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "fileId",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "properties": {
                  "file": {
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Updated file row",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string",
                      "example": "cmpfile_…"
                    },
                    "name": {
                      "type": "string",
                      "example": "hero.png"
                    },
                    "parentFolderId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "size": {
                      "type": "integer",
                      "description": "Bytes."
                    },
                    "mimeType": {
                      "type": "string",
                      "example": "image/png"
                    },
                    "thumbUrl": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "Server-generated 256-px webp URL. Null for non-raster files."
                    },
                    "starred": {
                      "type": "boolean"
                    },
                    "starredAt": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "format": "date-time"
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "tags": {
                      "type": "array",
                      "items": {
                        "type": "string"
                      }
                    },
                    "exif": {
                      "type": [
                        "object",
                        "null"
                      ],
                      "additionalProperties": {}
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "parentFolderId",
                    "size",
                    "mimeType",
                    "thumbUrl",
                    "createdAt",
                    "updatedAt"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "MIME category mismatch",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/files/zip": {
      "post": {
        "summary": "Bulk download multiple files as a zip",
        "description": "Capped at 50 files per request and 500 MB total uncompressed. Duplicate filenames are deduped server-side (`photo.jpg`, `photo (2).jpg`).",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "fileIds": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "maxItems": 50
                  },
                  "surfaceSlug": {
                    "type": "string"
                  }
                },
                "required": [
                  "fileIds",
                  "surfaceSlug"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "application/zip stream",
            "content": {
              "application/zip": {
                "schema": {
                  "format": "binary"
                }
              }
            }
          },
          "400": {
            "description": "Bundle exceeds 500 MB",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Unknown fileId or archived file",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/files/{fileId}/preview": {
      "get": {
        "summary": "Text-bytes preview for small text/code files",
        "description": "Returns the raw text bytes for files ≤256 KB with a text-like MIME (text/*, application/json, yaml, xml, js, ts, sh). Used by the in-browser code preview. Returns `{ id, name, mimeType, size, text }`.",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          },
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "fileId",
            "in": "path"
          }
        ],
        "responses": {
          "200": {
            "description": "Text payload",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "mimeType": {
                      "type": "string"
                    },
                    "size": {
                      "type": "integer"
                    },
                    "text": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "mimeType",
                    "size",
                    "text"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "MIME not previewable or oversize",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/folders": {
      "post": {
        "summary": "Create a folder",
        "tags": [
          "Files"
        ],
        "security": [
          {
            "bearer": []
          }
        ],
        "parameters": [
          {
            "schema": {
              "type": "string"
            },
            "required": true,
            "name": "slug",
            "in": "path"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "surfaceSlug": {
                    "type": "string"
                  },
                  "parentFolderId": {
                    "type": [
                      "string",
                      "null"
                    ]
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 255
                  }
                },
                "required": [
                  "surfaceSlug",
                  "name"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Folder created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "name": {
                      "type": "string"
                    },
                    "parentFolderId": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "position": {
                      "type": "integer"
                    },
                    "createdAt": {
                      "type": "string",
                      "format": "date-time"
                    },
                    "updatedAt": {
                      "type": "string",
                      "format": "date-time"
                    }
                  },
                  "required": [
                    "id",
                    "name",
                    "parentFolderId",
                    "position",
                    "createdAt",
                    "updatedAt"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}