Surfaces
A workspace holds one or more surfaces (tabs). Each surface is either a typed-row table or a TipTap rich-text doc. These endpoints add, list, reorder, rewrite the column schema, and remove tabs.
Generated from src/lib/api-paths/surfaces.ts: what you see here matches what the runtime validates.
get/api/workspaces/{slug}/surfaces
List surfaces in a workspace
Returns every surface (tab) in the workspace, in tab order.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Surface list. |
403 | Error | Caller can't access this workspace. |
post/api/workspaces/{slug}/surfaces
Add a surface (tab)
Append a new surface to the workspace. Editor role required.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
kind | "table" | "doc" | yes | Whether this tab is a typed-row table or a TipTap rich-text doc. |
name | string | no | Display name. Auto-generated if omitted. |
slug | string | no | URL slug. Auto-derived from name if omitted. |
columns | object[] | no | Optional initial columns for `kind: 'table'`. Defaults to Title/Status/Notes when omitted. Ignored on doc surfaces. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Created. |
403 | Error | Caller lacks editor role. |
patch/api/workspaces/{slug}/surfaces/{surfaceSlug}
Rename, reslug, reorder, OR replace a surface's column schema
Rename, change the URL slug, move a surface within its workspace's tab strip, OR replace the column schema (table surfaces only). Pass any subset of `name`, `slug`, `position`, `columns`. Position uses 0-based indexing and other tabs shift to keep positions contiguous. Column replace fires `surface.columns_updated`; row.data keys not in the new schema are preserved on disk. Editor role required. Slug renames preserve old URLs via the surface alias table.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes | |
surfaceSlug | string | yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | no | New display name. |
slug | string | no | New URL slug. Lowercase kebab-case, 3-64 chars. Must be unique within the workspace; old slug stays redirectable via the surface alias table. |
position | integer | no | Optional reorder. Equivalent to POST /surfaces/{slug}/move when only repositioning. |
columns | object[] | no | Wholesale replacement of the table surface's column schema. Table surfaces only — doc/html surfaces 400 with a table-only error. Each ColumnDef: `{ key, label, type, position, width?, hidden?, description?, options? }`. `type` ∈ text | longtext | url | status | owner | date | number. `options` is required on status/owner. Existing row.data keys not in the new column set are preserved on disk (they just stop rendering until a column with that key is added back). Fires `surface.columns_updated`. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Updated. |
403 | Error | Caller lacks editor role. |
409 | Error | Slug collides with another surface in the workspace. |
delete/api/workspaces/{slug}/surfaces/{surfaceSlug}
Delete a surface
Remove a tab. The workspace must keep at least one surface; deleting the last one returns 400.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes | |
surfaceSlug | string | yes |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Deleted. |
400 | Error | Workspace would have no surfaces left. |
post/api/workspaces/{slug}/surfaces/{surfaceSlug}/move
Reorder a surface
Change a surface's tab position. Other tabs shift accordingly.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes | |
surfaceSlug | string | yes |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
position | integer | yes | New 0-indexed tab position. Other tabs shift to accommodate. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Moved. |
Frequently asked questions
- How do I list every tab in a Dock workspace?
- GET `/api/workspaces/:slug/surfaces`. Returns each surface's id, slug, name, kind (`table` or `doc`), and tab position. Pass `?archived=true` to include archived surfaces.
- How do I add a new tab to a Dock workspace?
- POST `/api/workspaces/:slug/surfaces` with `{ kind, name, slug?, columns? }`. Slug auto-derives from name if omitted. For `kind: 'table'`, optionally pass `columns` to override the default Title/Status/Notes triple.
- How do I rename a Dock surface?
- PATCH `/api/workspaces/:slug/surfaces/:surfaceSlug` with `{ name }`. Pass `{ slug: 'new-slug' }` to also change the URL slug; the old slug stays redirectable. Pass `{ position }` to reorder. Editor role required.
- How do I replace the column schema of a Dock table surface?
- PATCH `/api/workspaces/:slug/surfaces/:surfaceSlug` with `{ columns: [...] }`. Wholesale replacement: pass the FULL ColumnDef[] you want, server applies it atomically. Each entry: `{ key, label, type, position, width?, hidden?, description?, options? }`. `type` ∈ `text | longtext | url | status | owner | date | number`; `options` is required for `status` and `owner`. Doc/html surfaces 400 with a table-only error. Existing row.data keys not covered by the new columns are preserved on disk (they just stop rendering in the UI until a column with that key is added back). Editor role required. Fires `surface.columns_updated`.
- Can I use the MCP or CLI to set columns on an existing Dock surface?
- Yes. MCP `update_surface(columns=[...])` mirrors the REST PATCH. CLI: `dock surface set-columns <workspace> <surface-slug> --from cols.json` (or `--json '<array>'`, or pipe stdin). Same `ColumnDef[]` payload across all three. Doc/html surfaces reject in every transport.
- How do I delete a tab from a Dock workspace?
- DELETE `/api/workspaces/:slug/surfaces/:surfaceSlug`. Soft-archive: rows + doc body preserved for restore. Cannot archive the only live surface; create another first. Editor role required.
- How do I reorder Dock surfaces (move a tab)?
- POST `/api/workspaces/:slug/surfaces/:surfaceSlug/move` with `{ position }`. 0-based; other tabs shift to keep positions contiguous. Or use PATCH on the same surface with `{ position }`; same effect.
- Can a Dock workspace have only doc surfaces (no table)?
- Yes. A workspace can hold any combination of table and doc surfaces, one or many of either kind, including all-doc or all-table. The workspace `mode` field is the default-view hint for the first tab opened.
- Can I move a Dock surface to a different workspace?
- Yes. POST `/api/workspaces/:slug/surfaces/:surfaceSlug/move` with `{ destinationWorkspaceSlug }` (in the same org). All rows / doc body / comments move atomically. Editor on both source and destination required.
- How do I tell which surface a row belongs to in Dock?
- Every row response includes `surface_slug` (the sheet it lives on). For multi-surface workspaces, `list_rows` and the row API both surface this. Single-sheet workspaces (back-compat) show the primary surface's slug.
- Can my AI agent target a specific Dock surface when writing rows?
- Yes. POST `/api/workspaces/:slug/rows` with `surface` (slug) or `surfaceId` to pick the target. Omit both to fall through to the workspace's primary table surface. MCP `create_row` accepts the same arg shape.
- How does Dock attribute who created or archived a surface?
- Surface create + archive both stamp `principalId + principalType` on the surface row. The surface list response renders the agent orb / human face for the creator; the archived view shows the archiver. Same attribution model as workspaces and rows.
Related
- Workspaces API: surfaces live inside workspaces.
- Rows API: write to a table surface.
- Doc API: write to a doc surface.