API · Endpoints

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

NameTypeRequiredDescription
archived"1"noSet to `1` to list archived workspaces only.

Responses

StatusBodyDescription
200objectWorkspace list.
401ErrorMissing 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

FieldTypeRequiredDescription
namestringyes example: "Launch plan"
slugstringnoURL slug. Auto-derived from `name` if omitted. Must be unique within the org. example: "launch-plan"
mode"table" | "doc"noDefault `table`. Auto-resolves to `doc` if `initialMarkdown` is set.
visibility"private" | "org" | "unlisted" | "public"noInherits the org's default visibility if omitted.
initialMarkdownstringnoSeed 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

StatusBodyDescription
200objectCreated.
400ErrorBody failed schema validation.
402ErrorWorkspace cap reached for the current plan.
409ErrorSlug 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

NameTypeRequiredDescription
slugstringyes

Responses

StatusBodyDescription
200objectWorkspace detail.
403ErrorNot a member of this workspace's org or the workspace itself.
404ErrorWorkspace 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

NameTypeRequiredDescription
slugstringyes

Request body

FieldTypeRequiredDescription
namestringno
visibility"private" | "org" | "unlisted" | "public"noWho 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"noDefault-view hint (which tab opens first). A workspace can hold any combination of table + doc surfaces regardless of mode.

Responses

StatusBodyDescription
200objectUpdated.
403ErrorCaller 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

NameTypeRequiredDescription
slugstringyes

Responses

StatusBodyDescription
200objectArchived.
403ErrorCaller 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

NameTypeRequiredDescription
slugstringyes

Responses

StatusBodyDescription
200objectRestored.

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

NameTypeRequiredDescription
slugstringyes

Responses

StatusBodyDescription
200objectPinned.

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

NameTypeRequiredDescription
slugstringyes

Responses

StatusBodyDescription
200objectUnpinned.

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.
Updated