Help
Help
Documents
Documents are markdown notes you own. They support folder organisation, full-text search, image embedding, templates, and a delta-sync mechanism for offline-capable clients. All document-creation endpoints require a subscription.
For organising documents into folders, see Document Folders.
Folder scoping (avoid silent data loss).
GET /api/documentsreturns only root documents (folderId: null) and ignores any?folderIdquery param.POST /api/documentsalways creates at root: there is nofolderIdin its body. To create or list documents inside a folder you must usePOST/GET /api/documents/folders/{id}/documents.PUTandPATCH /api/documents/{id}acceptfolderIdto move a document into (or out of) a folder.
Endpoint table
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /api/documents | Session or Bearer | List root-level documents (folderId is null), ordered by relativePath. |
| POST | /api/documents | Session or Bearer | Create a root-level document. Subscriber only. |
| GET | /api/documents/:id | Session or Bearer | Get a document. Owner sees everything; public documents are readable by anyone authenticated. |
| PUT | /api/documents/:id | Session or Bearer | Update a document (title, content, isPublic, folderId). |
| PATCH | /api/documents/:id | Session or Bearer | Partial update with optional optimistic concurrency via an If-Match header. Same fields as PUT; increments version. |
| DELETE | /api/documents/:id | Session or Bearer | Soft-delete; cascades blob image cleanup. |
| GET | /api/documents/:id/collaborators | Session or Bearer | List a document's collaborators. Owner only. |
| POST | /api/documents/:id/collaborators | Session or Bearer | Share a document with a user. Owner only. Body: { userId, role? }. |
| GET | /api/documents/:id/collaborators/users | Session or Bearer | Search users to add as collaborators (excludes owner + existing collaborators). Owner only. |
| PUT | /api/documents/:id/collaborators/:userId | Session or Bearer | Change a collaborator's role. Owner only. Body: { role }. |
| DELETE | /api/documents/:id/collaborators/:userId | Session or Bearer | Revoke a user's access to the document. Owner only. |
| GET | /api/documents/:id/share-links | Session or Bearer | List a document's active tokenized share links. Owner only. |
| POST | /api/documents/:id/share-links | Session or Bearer | Create a tokenized share link. Owner only. Subscriber only. |
| DELETE | /api/documents/:id/share-links/:token | Session or Bearer | Revoke a share link. Owner only. |
| GET | /api/documents/shared/:token | Optional | Resolve a share link for viewing (anonymous read for Viewer links). |
| POST | /api/documents/shared/:token | Session only | Claim an Editor/Admin share link as the signed-in user. |
| GET | /api/documents/search | Session or Bearer | Full-text search of your own documents. |
| GET | /api/documents/sync | Session or Bearer | Delta sync (pass ?lastSyncAt=<ISO> for incremental). |
| POST | /api/documents/sync | Session or Bearer | Batch apply create/update/delete operations in one request. |
| POST | /api/documents/:id/images/upload | Session or Bearer | Upload an image to embed in a document. Subscriber only. |
| GET | /api/documents/templates | Session or Bearer | List document templates. |
| POST | /api/documents/templates/seed-defaults | Session or Bearer | Seed your account with the default starter templates. |
| POST | /api/documents/from-template | Session or Bearer | Create a document from a template. Subscriber only. |
Creating a document
POST /api/documents
Content-Type: application/json
{
"title": "API Integration Notes",
"content": "# Notes\n\nHere are my integration notes...",
"isPublic": false
}
Response (201): the created document is returned under document:
{
"message": "Document created successfully",
"document": {
"id": "doc_qrs001",
"title": "API Integration Notes",
"content": "# Notes\n\nHere are my integration notes...",
"isPublic": false,
"folderId": null,
"relativePath": "api-integration-notes.md",
"createdAt": "2025-06-11T09:00:00.000Z",
"updatedAt": "2025-06-11T09:00:00.000Z"
}
}
relativePath is auto-generated from title if omitted. A content hash (contentHash) is computed server-side and used by the delta-sync engine.
Partial updates & optimistic concurrency
PATCH /api/documents/{id} applies a partial update. It accepts the same fields as PUT (title, content, isPublic, folderId) and each successful update increments the document's version.
To avoid clobbering a concurrent edit, send the version you last read in an If-Match request header (its value is the current integer version):
PATCH /api/documents/doc_qrs001
If-Match: 7
Content-Type: application/json
{ "content": "# Notes\n\nUpdated body..." }
If the header is omitted the update is applied unconditionally. If it is present and does not match the server's current version, the request fails without applying any change:
409 Conflict
{
"error": "version_conflict",
"currentVersion": 9,
"serverDocument": { "id": "doc_qrs001", "version": 9, "...": "..." }
}
Re-read the returned serverDocument, reconcile your local changes, then retry with the new currentVersion in If-Match.
Collaborators & sharing
A document owner can share a document with other users at one of three access levels. Combined with the owner, this yields four roles:
| Role | Can read | Can edit content | Can edit title / visibility / folder | Can delete | Can manage collaborators |
|---|---|---|---|---|---|
| owner | yes | yes | yes | yes | yes |
| manager | yes | yes | yes | yes | no (owner only) |
| collaborator | yes | yes | no | no | no |
| watcher | yes | no (read-only) | no | no | no |
All collaborator-management endpoints are owner only and accept a session cookie or a Bearer token.
Listing collaborators
GET /api/documents/doc_qrs001/collaborators?limit=20&offset=0
{
"collaborators": [
{
"id": "dc_001",
"userId": "u2",
"role": "collaborator",
"createdAt": "2025-06-11T09:00:00.000Z",
"user": { "id": "u2", "username": "someone", "displayName": "Some One", "avatar": null }
}
],
"pagination": { "total": 1, "limit": 20, "offset": 0, "hasMore": false }
}
Adding a collaborator
POST /api/documents/doc_qrs001/collaborators
Content-Type: application/json
{ "userId": "u2", "role": "collaborator", "notify": true }
role is one of watcher, collaborator, or manager and defaults to watcher when omitted or invalid. notify is an optional boolean (default true): on a new grant the recipient always gets an in-app notification, and unless notify is false they also get an email (a "silent" share sends the in-app notification only). Adding a collaborator is a sharing action and is subscriber-gated: a free (non-subscriber) owner receives 403 { "error": "Subscribe to share documents." }.
Returns { "collaborating": true }: 201 when newly added (this is when a notification fires), 200 if the user was already a collaborator (idempotent, no notification). Returns 400 if userId is missing or if you try to add yourself, and 404 if the target user or document does not exist.
Finding users to add
GET /api/documents/doc_qrs001/collaborators/users?search=some&limit=50&offset=0
Searches users by username, displayName, or email, excluding the owner and existing collaborators. Returns { users, total, pagination }.
Changing a role or revoking access
PUT /api/documents/doc_qrs001/collaborators/u2
Content-Type: application/json
{ "role": "manager", "notify": true }
Returns { "role": "manager" }; an invalid or missing role returns 400, and a user not currently on the document returns 404. Changing a role is subscriber-gated (403 for free owners). notify (optional, default true) works as it does on add, but a notification only fires when the role actually changes: re-setting the same role is a silent no-op. Revoking access (DELETE) is not subscriber-gated so a downgraded owner can always remove people.
DELETE /api/documents/doc_qrs001/collaborators/u2
Revokes the user's access. Returns { "removed": true }.
Share links (share by link, not by person)
Instead of naming a user, an owner can mint a secret tokenized share link that grants a role (watcher/collaborator/manager) to anyone who opens it: POST /api/documents/:id/share-links. Creating a link is subscriber-gated (403 for free owners); listing and revoking are owner-only. Recipients open /documents/shared/:token to view, and (for Editor/Admin links) sign in to claim the grant. The full request/response reference for share links lives on the Sharing & Share Links page.
Delta sync
Delta sync is the efficient way to keep a local copy up to date. On first run, omit lastSyncAt to fetch everything. On subsequent runs, pass the timestamp returned by the previous sync:
GET /api/documents/sync?lastSyncAt=2025-06-10T00:00:00.000Z
Authorization: Bearer 3f1c9e...<64 hex chars>...a8
{
"folders": [ ... ],
"documents": [
{ "id": "doc_qrs001", "title": "API Integration Notes", "updatedAt": "2025-06-11T09:00:00.000Z", "deletedAt": null }
],
"lastSyncAt": "2025-06-11T09:15:00.000Z"
}
Each document is a full document row. Deletions are conveyed by deletedAt: a document with a non-null deletedAt has been soft-deleted and should be removed from the local copy (there is no deleted boolean). A delta sync (with ?lastSyncAt=) includes soft-deleted documents so the client learns about deletions; a full sync (no lastSyncAt) returns only active documents. Use the returned lastSyncAt as the next request's lastSyncAt.
The POST /api/documents/sync form accepts a batch of operations (create/update/delete) and applies them atomically, useful for two-way sync clients pushing local edits.
Search
GET /api/documents/search?q=integration&limit=20
Searches across title and content. Only your own documents are searched.
Templates
GET /api/documents/templates # list available templates
POST /api/documents/templates/seed-defaults # add the defaults to your account
POST /api/documents/from-template # create a document from a template
Content-Type: application/json
{ "templateDocumentId": "tpl_default_meeting_notes", "targetFolderId": null }
templateDocumentId (required) is the ID of a template document from GET /api/documents/templates. targetFolderId is optional (null = create at root; must be a folder you own). The document's title is copied from the template; there is no title field on this request.
Image uploads
POST /api/documents/doc_qrs001/images/upload
Content-Type: multipart/form-data
file=<binary>
Returns the uploaded image URL. Embed it in markdown with . Soft-deleting the document cascades the cleanup of these blob images.
Image upload requires both a subscription and a verified email: an unverified account receives 403 "Email verification required to post images.", and a free account receives 403 "Subscribe to unlock image posting.".
Related
- Documents (Help Center): the user-facing guide to writing, organising, and sharing documents.
- Document Folders: folder hierarchy for organising documents.
- Sharing & Share Links: tokenized share links and per-person roles for documents.
- API overview: base URL, authentication at a glance, and response conventions.
- API explorer: try document endpoints live with the interactive Swagger console.