Workspaces
Workspace CRUD plus archive, unarchive, and personal pin. The unit of shared work in Dock, see Web → Workspaces for the conceptual model.
These docs are generated from the same Zod schemas the runtime uses to validate requests, so the field names, types, and required-vs-optional flags below match production exactly. Source: src/lib/api-paths/workspaces.ts.
get/api/workspaces
List workspaces
List every workspace the caller can access. Pass `?archived=1` to list soft-archived workspaces only; the default view excludes them.
Auth: Bearer token (API key or OAuth access token).
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
archived | "1" | no | Set to `1` to list archived workspaces only. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Workspace list. |
401 | Error | Missing or invalid bearer token. |
post/api/workspaces
Create a workspace
Create a new workspace. Returns the created row. The caller becomes its owner. Visibility defaults to the org's default if omitted.
Auth: Bearer token (API key or OAuth access token).
Request body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | yes | example: "Launch plan" |
slug | string | no | URL slug. Auto-derived from `name` if omitted. Must be unique within the org. example: "launch-plan" |
mode | "table" | "doc" | no | Default `table`. Auto-resolves to `doc` if `initialMarkdown` is set. |
visibility | "private" | "org" | "unlisted" | "public" | no | Inherits the org's default visibility if omitted. |
initialMarkdown | string | no | 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). |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Created. |
400 | Error | Body failed schema validation. |
402 | Error | Workspace cap reached for the current plan. |
409 | Error | Slug already exists in the org. |
get/api/workspaces/{slug}
Get workspace detail
Fetch a workspace by slug, including columns, member count, mode, and visibility.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Workspace detail. |
403 | Error | Not a member of this workspace's org or the workspace itself. |
404 | Error | Workspace not found (or visibility hides it from the caller). |
patch/api/workspaces/{slug}
Update a workspace
Rename, change mode, or change visibility. Editor or owner 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 |
|---|---|---|---|
name | string | no | |
visibility | "private" | "org" | "unlisted" | "public" | no | 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 | "table" | "doc" | no | Default-view hint (which tab opens first). A workspace can hold any combination of table + doc surfaces regardless of mode. |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Updated. |
403 | Error | Caller lacks editor role. |
delete/api/workspaces/{slug}
Archive a workspace
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.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Archived. |
403 | Error | Caller lacks editor role. |
post/api/workspaces/{slug}/unarchive
Restore an archived workspace
Reverse a soft-archive. Idempotent on workspaces that aren't archived. Emits a `workspace.unarchived` event carrying the previous archive timestamp. Editor role required.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Restored. |
post/api/workspaces/{slug}/pin
Pin a workspace
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).
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Pinned. |
delete/api/workspaces/{slug}/pin
Unpin a workspace
Remove the calling principal's pin. Idempotent.
Auth: Bearer token (API key or OAuth access token).
Path parameters
| Name | Type | Required | Description |
|---|---|---|---|
slug | string | yes |
Responses
| Status | Body | Description |
|---|---|---|
200 | object | Unpinned. |
Frequently asked questions
- How do I create a Dock workspace via the REST API?
- POST `/api/workspaces` with `{ name, slug?, mode?, visibility?, initialMarkdown? }`. The `slug` auto-derives from `name` if omitted. Visibility defaults to `org` for multi-member orgs, `private` for solo.
- How do I list every Dock workspace I have access to?
- GET `/api/workspaces` returns workspaces the calling principal can read, with hydrated `createdBy`, `role`, `pinnedAt`. Pass `?archived=1` to list archived only; default excludes archived.
- How do I create a doc-mode Dock workspace with seeded content?
- POST `/api/workspaces` with `initialMarkdown: "# My doc\n\n…"`. Mode auto-resolves to `doc`; the default-column scaffolding is skipped. Markdown is converted server-side via the same path PUT /doc uses.
- How do I rename a Dock workspace via the API?
- PATCH `/api/workspaces/:slug` with `{ name }`. Slug stays the same; old URLs keep working. To change the slug too, pass `{ slug: "new-slug" }`; the old slug stays redirectable via the alias table.
- How do I archive a Dock workspace via the API?
- DELETE `/api/workspaces/:slug` (soft-archive). Editor role required. Stamps `archivedAt + archivedByPrincipalId + archivedByPrincipalType` so the Archived tab can render attribution. Rows + doc + members + events stay intact.
- How do I unarchive a Dock workspace?
- POST `/api/workspaces/:slug/unarchive`. Editor role required. Idempotent on already-live workspaces. Emits a `workspace.unarchived` event carrying the previous archive timestamp.
- How do I pin a Dock workspace via the API?
- POST `/api/workspaces/:slug/pin`. Pin is per-principal (your pin doesn't pin for the whole org). Requires an actual membership row; org-visibility virtual viewers can't pin.
- How do I change a Dock workspace's visibility?
- PATCH `/api/workspaces/:slug` with `{ visibility: "private" | "org" | "unlisted" | "public" }`. Visibility widening (private → org/unlisted/public, etc.) is consent-gated; pass `consent_mode: "web"` for the click-to-approve flow.
- How does the Dock API attribute who created a workspace?
- Every workspace row carries `createdByPrincipalId` + `createdByPrincipalType`. Agent-created workspaces stamp the agent (not its owner), so the audit trail accurately renders an agent orb in the dashboard creator chip.
- How do I move a Dock workspace to a different org?
- Not directly; orgs own workspaces. To migrate content, use surface-move (`POST /api/workspaces/:slug/surfaces/:surfaceSlug/move`) to relocate individual surfaces between workspaces in the same org. Cross-org workspace move is on the roadmap.
Related
- Web → Workspaces: conceptual model (surfaces, visibility, pinning, archiving) for the same objects.
- API authentication: how to get a Bearer token.
- Error codes: full catalog.
- /openapi.json: full machine-readable spec.