{
  "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"
    }
  },
  "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"
          },
          "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": {
      "parameters": [
        {
          "in": "path",
          "name": "slug",
          "required": true,
          "schema": {
            "type": "string",
            "pattern": "^[a-z0-9]+(-[a-z0-9]+)*$"
          }
        }
      ],
      "get": {
        "tags": [
          "Columns"
        ],
        "summary": "Column schema",
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          }
        }
      },
      "post": {
        "tags": [
          "Columns"
        ],
        "summary": "Append a single column",
        "description": "Append one column to the existing schema. Server auto-computes `position` so the contiguity invariant (0, 1, 2, …) holds. `key` must be unique → 409 on collision. Editor role required.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "column"
                ],
                "properties": {
                  "column": {
                    "$ref": "#/components/schemas/ColumnDef"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          },
          "409": {
            "description": "Error.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Columns"
        ],
        "summary": "Replace column schema",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "columns"
                ],
                "properties": {
                  "columns": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/ColumnDef"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK.",
            "content": {
              "application/json": {}
            }
          }
        }
      }
    },
    "/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."
                          }
                        },
                        "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."
                  }
                },
                "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."
                        }
                      },
                      "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}": {
      "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."
                        }
                      },
                      "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.",
        "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
                  },
                  "surfaceId": {
                    "type": "string",
                    "minLength": 1
                  },
                  "surface": {
                    "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.",
        "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": "integer",
                    "minimum": 0
                  },
                  "surfaceId": {
                    "type": "string",
                    "minLength": 1
                  },
                  "surface": {
                    "type": "string",
                    "minLength": 1
                  }
                },
                "required": [
                  "data"
                ]
              }
            }
          }
        },
        "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
                        },
                        "surfaceId": {
                          "type": "string",
                          "minLength": 1
                        },
                        "surface": {
                          "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
                  }
                },
                "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"
                  ]
                }
              }
            }
          }
        }
      }
    },
    "/api/workspaces/{slug}/comments": {
      "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": [
                              "surface"
                            ]
                          },
                          "surfaceSlug": {
                            "type": "string",
                            "minLength": 1
                          }
                        },
                        "required": [
                          "type",
                          "surfaceSlug"
                        ]
                      },
                      {
                        "type": "object",
                        "properties": {
                          "type": {
                            "type": "string",
                            "enum": [
                              "workspace"
                            ]
                          }
                        },
                        "required": [
                          "type"
                        ]
                      }
                    ]
                  },
                  "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": {
      "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"
                      ]
                    },
                    "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"
                  ]
                }
              }
            }
          }
        }
      }
    }
  }
}