Docs
Knobs Docs are collaborative rich-text documents. REST covers metadata, sharing, content reads, trash, image assets, and import/export. Live editing does not flow through REST — the apps push CRDT frames over the realtime connection after joining via the open call; a REST client reads materialized content instead.
All routes are workspace-scoped and accept a session JWT or API key. Docs are private by default with per-doc ACLs: a doc you can’t view reads as 404.
Documents
Section titled “Documents”| Endpoint | Description |
|---|---|
GET /v1/workspaces/{wid}/docs |
List docs you can read (?limit=) |
POST /v1/workspaces/{wid}/docs |
Create {title} → 201 — private to you by default |
GET /v1/workspaces/{wid}/docs/{did} |
Doc metadata + latest snapshot ref (view access) |
PATCH /v1/workspaces/{wid}/docs/{did} |
Exactly one of {title} (rename, edit access), {trash: true}, or {restore: true} (owner/admin) |
DELETE /v1/workspaces/{wid}/docs/{did} |
Permanently purge a trashed doc → 202 {purging: true} (async) |
POST /v1/workspaces/{wid}/docs/{did}/open |
Join for live editing: verifies access, returns metadata + a signed snapshot URL. Used by collaborative clients; plain REST readers don’t need it |
GET /v1/workspaces/{wid}/docs/trash |
List trashed docs |
POST /v1/workspaces/{wid}/docs/trash:empty |
Purge everything in the trash → 202 {purging: n} |
Reading content
Section titled “Reading content”| Endpoint | Description |
|---|---|
GET /v1/workspaces/{wid}/docs/{did}/content |
Materialized document bytes; ?format=html (default) or ?format=md. Serves a strong ETag and honors If-None-Match |
curl -H "Authorization: Bearer knak_..." \ "https://api.knobs.io/v1/workspaces/{wid}/docs/{did}/content?format=md"The response body is the document itself (text/html or text/markdown), not JSON. Heavier formats (DOCX, PDF, …) go through the async export flow below.
Sharing
Section titled “Sharing”The access model is ownerUid + workspaceAccess (none/view/comment/edit, what any workspace member gets) + grants (per-principal levels; principals are user uids or group ids grp_…). Workspace admins/owners implicitly have owner-level access.
| Endpoint | Description |
|---|---|
GET /v1/workspaces/{wid}/docs/{did}/access |
The sharing panel: {ownerUid, workspaceAccess, grants} (owner or workspace admin) |
PUT /v1/workspaces/{wid}/docs/{did}/access |
Wholesale replace {workspaceAccess, grants} — the owner’s grant is server-maintained and must not appear |
curl -X PUT https://api.knobs.io/v1/workspaces/{wid}/docs/{did}/access \ -H "Authorization: Bearer knak_..." \ -H "Content-Type: application/json" \ -d '{"workspaceAccess": "view", "grants": {"u_5ac2…": "edit", "grp_design…": "comment"}}'Comments
Section titled “Comments”Anchored comment threads live on the doc. A thread carries a plain-text body, optional mentions (member uids), optional selection anchors (anchorFrom/anchorTo, opaque editor-generated strings) with a quotedText fallback, embedded replies, and a resolved flag. Listing requires view access; adding, replying, and resolving require comment access; editing a body is author-only; deleting is author or owner/admin.
| Endpoint | Description |
|---|---|
GET /v1/workspaces/{wid}/docs/{did}/comments |
List threads, oldest first → {comments} |
POST /v1/workspaces/{wid}/docs/{did}/comments |
Start a thread {body, mentions?, anchorFrom?, anchorTo?, quotedText?, suggestionId?} → the thread |
POST /v1/workspaces/{wid}/docs/{did}/comments/{cid}/replies |
Reply {body, mentions?} → the updated thread (≤100 replies) |
POST /v1/workspaces/{wid}/docs/{did}/comments/{cid}/resolve |
`{resolved: true |
PATCH /v1/workspaces/{wid}/docs/{did}/comments/{cid} |
Edit the body {body} (author only) |
DELETE /v1/workspaces/{wid}/docs/{did}/comments/{cid} |
Delete the thread → 204 |
Versions, turns, and redlines
Section titled “Versions, turns, and redlines”A version is the document’s state pinned under a name. A turn is a version plus exchange metadata — one step of a redline negotiation. Compare synthesizes a redline (tracked changes) between any two versions. Restore is never destructive: it appends an edit that brings the live document back to the pinned state, so history — including the restore itself — is preserved.
| Endpoint | Description |
|---|---|
GET /v1/workspaces/{wid}/docs/{did}/versions |
Pinned versions, newest first → {versions} |
POST /v1/workspaces/{wid}/docs/{did}/versions |
Pin the current state {name} → the version (edit access) |
POST /v1/workspaces/{wid}/docs/{did}/versions/{vid}/restore |
Restore the live doc to a pinned version (edit access) |
GET /v1/workspaces/{wid}/docs/{did}/versions/compare |
?from={vid}&to={vid or live} — the redline between two versions → {redline} (ProseMirror JSON); add format=docx to download it as a tracked-changes Word file |
GET /v1/workspaces/{wid}/docs/{did}/turns |
The exchange timeline, newest first → {turns} |
POST /v1/workspaces/{wid}/docs/{did}/turns |
Pin the current state as a turn {name, direction: sent|received|internal, counterparty?} (edit access) |
POST /v1/workspaces/{wid}/docs/{did}/turns/export-pair |
“Send to counsel”: {name, counterparty?, scrub?} → 202 with a sent turn plus two export jobs (a clean and a tracked-changes Word file) whose ids also land on the turn (edit access) |
POST /v1/workspaces/{wid}/docs/{did}/turns/import |
Import a returned Word file as a turn: multipart file (.docx) + name + optional counterparty → 202 {job}. Tracked changes land as suggestions (attributed to the counterparty when the file is clean or the doc moved on); its comments become threads; the pre-import state is pinned for one-click undo (edit access) |
GET /v1/workspaces/{wid}/docs/{did}/turns/imports/{jid} |
Turn-import job status → {job} with turnId, preImportVersionId, suggestionCount, and warnings when done |
POST /v1/workspaces/{wid}/docs/{did}/suggestions/accept-all |
Apply every pending suggestion (edit access) |
POST /v1/workspaces/{wid}/docs/{did}/suggestions/reject-all |
Undo every pending suggestion (edit access) |
Guest reviewers
Section titled “Guest reviewers”External reviewers open one document from a private magic link — no Knobs account. Guests are always commenters: everything they type lands as suggestions, and their Word-style comments appear under their email address. Links expire after 30 days; revoking one cuts access immediately, including live editing sessions.
| Endpoint | Description |
|---|---|
GET /v1/workspaces/{wid}/docs/{did}/guests |
List a doc’s guest links (owner/admin) → {guests} |
POST /v1/workspaces/{wid}/docs/{did}/guests |
Create a guest link {email} → {guest, link} — the link is returned once; share it yourself (owner/admin) |
DELETE /v1/workspaces/{wid}/docs/{did}/guests/{gid} |
Revoke a guest link |
POST /v1/guest/sessions |
Public: redeem a link’s token {token} → a sign-in credential plus the document’s coordinates. Invalid, expired, and revoked links all answer 404 |
GET /v1/guest/doc |
Guest: the document’s metadata (guest credential as bearer) |
POST /v1/guest/doc/open |
Guest: join the live document |
GET /v1/guest/doc/comments |
Guest: list comment threads |
POST /v1/guest/doc/comments |
Guest: start a thread |
POST /v1/guest/doc/comments/{cid}/replies |
Guest: reply to a thread |
POST /v1/guest/doc/comments/{cid}/resolve |
Guest: resolve or reopen a thread |
GET /v1/guest/doc/assets/{aid} |
Guest: resolve an image asset → {url} |
Google Docs
Section titled “Google Docs”Send a document to Google Docs as a native Google Doc — tracked changes become Google suggestions — let the other side edit there, then pull their edits back as a review turn. Requires connecting your Google account (per user, drive.file scope: Knobs only touches files it creates). If Google integration isn’t configured on the deployment, the status route says so — {configured:false} with a normal 200 — and the rest answer 503.
| Endpoint | Description |
|---|---|
GET /v1/users/me/connections/google/start |
Begin connecting → {url} — open it to grant access |
GET /v1/users/me/connections/google |
Connection status → {connected, email, configured}. configured:false means this deployment has no Google integration — a normal 200, so clients can hide the feature without treating it as an error |
DELETE /v1/users/me/connections/google |
Disconnect (Knobs forgets the credential) |
POST /v1/workspaces/{wid}/docs/{did}/google/link |
Bind the doc to a Google Doc {fileId} (edit access). Pushing without a link creates the file and links it automatically |
DELETE /v1/workspaces/{wid}/docs/{did}/google/link |
Unbind |
POST /v1/workspaces/{wid}/docs/{did}/google/push |
Send the doc {variant?: "redline"|"clean", scrub?} → {fileId, url}; records a sent turn. Redline (default) carries suggestions into Google |
POST /v1/workspaces/{wid}/docs/{did}/google/pull |
Import the Google Doc’s current state {name?} → 202 {job} — poll the turn-import job; edits land as suggestions on a received turn |
AI review
Section titled “AI review”AI works only through suggestions — it never edits the document directly. If AI isn’t configured on the deployment these routes answer 503.
| Endpoint | Description |
|---|---|
POST /v1/workspaces/{wid}/docs/{did}/turns/{tid}/analyze |
Ask AI to summarize and risk-rate a turn’s changes → 202; the result appears on the turn’s analysis (summary, per-change explanations with low/medium/high risk, flags) |
POST /v1/workspaces/{wid}/docs/{did}/ai/propose |
Ask AI to revise the document {instruction} → 202 {job}. The proposed edits land as ordinary suggestions authored ai:<your uid> — accept or reject them in the review panel |
GET /v1/workspaces/{wid}/docs/{did}/ai/jobs/{jid} |
AI revision job status → {job} with suggestionCount when done |
AI revision currently supports text documents (no images) without pending suggestions, up to ~120 KB of content.
Image assets
Section titled “Image assets”Editor images upload directly to storage via a signed URL; the doc references the stable asset id.
| Endpoint | Description |
|---|---|
POST /v1/workspaces/{wid}/docs/{did}/assets |
Start an upload {mime, size} → {assetId, url, headers} — PUT the bytes to url with headers (edit access) |
GET /v1/workspaces/{wid}/docs/{did}/assets/{aid} |
Resolve an asset → {url} (short-lived signed download URL; view access) |
Import & export
Section titled “Import & export”Both directions are async jobs. Supported formats include TXT, Markdown, HTML, DOCX, ODT, RTF, and (export-only) PDF.
| Endpoint | Description |
|---|---|
POST /v1/workspaces/{wid}/docs/import |
Multipart upload (file + optional title) → 202 {job} — the new doc is private to you |
GET /v1/workspaces/{wid}/doc-imports/{jid} |
Import job status → {job} (includes the doc id when done) |
POST /v1/workspaces/{wid}/docs/{did}/export |
Start an export {format, variant?, scrub?} → 202 {job}. variant: "redline" (DOCX only) keeps pending suggestions as Word tracked changes and includes the doc’s comments; scrub: true anonymizes authors and drops dates while keeping the markup. The default ("clean") exports with all suggestions accepted |
GET /v1/workspaces/{wid}/docs/{did}/exports/{jid} |
Export job status → {job, url} — url is a fresh signed download link once ready |
curl -X POST https://api.knobs.io/v1/workspaces/{wid}/docs/import \ -H "Authorization: Bearer knak_..." \ -F "file=@spec.docx" -F "title=Product spec"Import files are capped at 20 MiB (413 too_large); unsupported types return 400 unsupported_format.