Outlines
Outliner documents: a structure block like a page, with its node tree inside its own document rather than in the page tree.
10 operations. Every path is relative to the instance origin; every response body is JSON unless stated. The endpoint descriptions below come straight from the server’s own route table. See API for authentication, errors and pagination.
GET /api/v1/workspaces/{workspaceId}/outlines
List outlines, flat, in the order the sidebar draws them. With collectionId, one collection's — which needs read on it. Without, every outline in the workspace the caller may read, which is what a sidebar grouping documents by collection asks for: one request rather than one per collection. Both are filtered per block through the same permission and product gates, so omitting the collection widens the scope and relaxes nothing.
listOutlines · token scope: content:read
Path parameters
workspaceId· string (uuid) — required
Query parameters
collectionId· string (uuid)
Response 200 — application/json
items· object[] — requiredid· string (uuid) — requiredworkspaceId· string (uuid) — requiredcollectionId· string (uuid) — requiredtitle· string — requiredicon· string | null — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requireddeletedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
POST /api/v1/workspaces/{workspaceId}/outlines
Create an outline at the collection root. Requires edit on the collection; the body doc is created lazily on first collab connect.
createOutline · token scope: content:write
Path parameters
workspaceId· string (uuid) — required
Request body — application/json, required
collectionId· string (uuid) — requiredtitle· string — required, length 1–500icon· string — length 0–2048
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredcollectionId· string (uuid) — requiredtitle· string — requiredicon· string | null — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requireddeletedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
GET /api/v1/workspaces/{workspaceId}/outlines/{outlineId}
Fetch one outline (structure plane only). Requires read.
getOutline · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredoutlineId· string (uuid) — required
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredcollectionId· string (uuid) — requiredtitle· string — requiredicon· string | null — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requireddeletedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
PATCH /api/v1/workspaces/{workspaceId}/outlines/{outlineId}
Rename an outline or change its icon. Requires edit.
updateOutline · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredoutlineId· string (uuid) — required
Request body — application/json, required
title· string — length 1–500icon· string | null
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredcollectionId· string (uuid) — requiredtitle· string — requiredicon· string | null — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requireddeletedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
DELETE /api/v1/workspaces/{workspaceId}/outlines/{outlineId}
Move an outline to the trash (soft delete). Requires full.
trashOutline · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredoutlineId· string (uuid) — required
Response 200 — application/json
ok·true— required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
GET /api/v1/workspaces/{workspaceId}/outlines/{outlineId}/markdown
Fetch the outline's node tree as canonical outline Markdown (text/markdown with a strong ETag over the canonical bytes; ADR-0018, mirroring the ADR-0012 page surface). Requires read.
getOutlineMarkdown · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredoutlineId· string (uuid) — required
Response 200 — application/json
- string
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
PUT /api/v1/workspaces/{workspaceId}/outlines/{outlineId}/markdown
Replace an outline’s node tree from canonical outline Markdown (text/markdown; ADR-0018 amendment 8, mirroring the ADR-0012 page surface). Applied to the live document in one Yjs transaction, so an open Lithic tab sees it immediately. A row the Markdown did not change keeps its node id, its attachments and its place in a day plan; rows the Markdown drops are deleted. Supports If-Match/ETag optimistic concurrency (412 on mismatch); returns the stored canonical Markdown. A non-empty body that parses to no rows at all (prose rather than - bullets) is refused with a 400 instead of emptying the outline; send an EMPTY body to clear it. Requires edit.
updateOutlineMarkdown · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredoutlineId· string (uuid) — required
Request body — application/json, required
- string
Response 200 — application/json
- string
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
POST /api/v1/workspaces/{workspaceId}/outlines/{outlineId}/move
Reorder an outline among its collection’s outlines — beforeId/afterId name the siblings it lands between, neither appends. Outlines stay at the collection root. Requires edit.
moveOutline · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredoutlineId· string (uuid) — required
Request body — application/json, required
beforeId· string (uuid)afterId· string (uuid)
Response 200 — application/json
id· string (uuid) — requiredworkspaceId· string (uuid) — requiredcollectionId· string (uuid) — requiredtitle· string — requiredicon· string | null — requiredcreatedAt· string (date-time) — requiredupdatedAt· string (date-time) — requireddeletedAt· string (date-time) | null — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
GET /api/v1/workspaces/{workspaceId}/outlines/{outlineId}/pane-layout
The CALLING USER’s pane layout for this outline, or null where they have not arranged one. Personal by construction — no user id is accepted anywhere on the route, so it can only ever answer for whoever holds the session, and a colleague reading the same document keeps their own arrangement.
getPaneLayout · token scope: content:read
Path parameters
workspaceId· string (uuid) — requiredoutlineId· string (uuid) — required
Response 200 — application/json
panes· object[] — requiredid· string — required, length 1–∞type· string — required, length 1–∞view· string — required, length 1–∞size· number — requiredhidden· boolean
updatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64
PUT /api/v1/workspaces/{workspaceId}/outlines/{outlineId}/pane-layout
Replace the CALLING USER’s pane layout for this outline. A whole layout, never a partial one: a window that closes a pane is saying what the layout IS.
setPaneLayout · token scope: content:write
Path parameters
workspaceId· string (uuid) — requiredoutlineId· string (uuid) — required
Request body — application/json, required
panes· object[] — required, 0–16 itemsid· string — required, length 1–∞type· string — required, length 1–∞view· string — required, length 1–∞size· number — requiredhidden· boolean
Response 200 — application/json
panes· object[] — requiredid· string — required, length 1–∞type· string — required, length 1–∞view· string — required, length 1–∞size· number — requiredhidden· boolean
updatedAt· string (date-time) — required
Response default — application/json
error· object — requiredcode·"bad_request"|"validation_failed"|"unauthorized"|"forbidden"|"not_found"|"conflict"|"rate_limited"|"internal"— requiredmessage· string — requiredreason· string — length 1–64