Workspace API

REST endpoints for notes, kanban boards, and calendar events. All require Authorization: Bearer <token>.

Notes

Mounted at /api/notes. Notes are stored as markdown in SQLite and use delta-based (incremental) updates rather than full overwrites.

MethodPathDescription
GET /api/notes List all notes. Optional ?q= for full-text search across titles and content.
POST /api/notes Create a note. Body: { title, content }
GET /api/notes/:id Get a note by ID.
POST /api/notes/:id/delta Apply incremental delta changes to a note. Used by the rich-text editor for collaborative-style updates. Body: ProseMirror changeset.
DELETE /api/notes/:id Delete a note permanently.
POST /api/notes/link-preview Fetch Open Graph metadata for a URL. Body: { url }. Used by the editor to embed link previews.
POST /api/notes/:id/export/docx Export a note as a .docx file. Returns the file as an attachment download.
POST /api/notes/:id/export/pdf Export a note as a PDF. Returns the file as an attachment download.

Note: There is no PUT /api/notes/:id endpoint. All updates go through POST /:id/delta which applies incremental changes rather than replacing the full content.

Kanban columns

Mounted at /api/columns. Columns belong to a project (board). Reordering columns uses a dedicated /order endpoint.

MethodPathDescription
GET /api/columns Get all columns (scoped to authenticated user's workspace).
POST /api/columns Create a column. Body: { title, projectId }
PUT /api/columns/order Update the sort order of columns. Body: { columnIds: ["id1", "id2", ...] }
PUT /api/columns/:id Update a column. Body: { title }
DELETE /api/columns/:id Delete a column and all its cards.

Kanban cards

Mounted at /api/cards. Cards live inside columns and support checklists and file attachments. Attachment uploads use multipart/form-data.

MethodPathDescription
GET /api/cards/column/:columnId Get all cards in a column, ordered by position.
GET /api/cards/:id Get a single card with its checklist and attachments.
POST /api/cards Create a card. Accepts multipart/form-data with optional file attachments. Fields: title, columnId, description?, priority?, dueDate?
PUT /api/cards/:id Update a card. Body: any subset of card fields (title, description, priority, dueDate, progress).
DELETE /api/cards/:id Delete a card and its attachments.
POST /api/cards/:id/move Move a card to a different column and/or position. Body: { columnId, position? }
PUT /api/cards/:id/checklist Replace the full checklist. Body: { checklist: [{ text, completed }] }
POST /api/cards/:id/attachments Upload file attachment(s). multipart/form-data, field name file. Max 10 files, 10 MB each.
DELETE /api/cards/:id/attachments/:attachmentId Remove a specific attachment from a card.

Allowed attachment MIME types

Images (PNG, JPEG, GIF, WebP, SVG, BMP), documents (PDF, Word, Excel, PowerPoint), text/code (plain text, HTML, CSS, JS, JSON, XML, CSV), archives (ZIP, RAR, 7z, tar, gzip).

Calendar events

Mounted at /api/events. Events are scoped to the authenticated user. Time fields are ISO 8601 strings. The API accepts several flexible date/time input formats.

MethodPathDescription
GET /api/events List events. Optional ?startDate=ISO&endDate=ISO range filter, ?limit=500&offset=0 pagination.
GET /api/events/combined-data Same as list but returns events wrapped in { data: { events } } with totals. Useful for dashboard views.
POST /api/events Create an event. See event body below.
GET /api/events/:id Get an event by ID.
PUT /api/events/:id Update an event. Body: any subset of event fields.
DELETE /api/events/:id Delete an event.

Event body

The API accepts flexible date/time formats. Use whichever form is most convenient:

FieldTypeRequiredDescription
titlestringYesEvent title.
startTimeISO stringYes*Full ISO datetime. If provided with endTime, used directly.
endTimeISO stringYes*Must be after startTime.
startDate + startTimestringsAltDate YYYY-MM-DD + time HH:MM combined on the server.
date + start + endstringsAltSingle date with start/end times.
descriptionstringNoEvent notes or agenda.
locationstringNoPhysical or virtual location.
colorstringNoColor name (e.g. purple, blue). Default: purple.
isAllDaybooleanNoMark as an all-day event. Default: false.

Example

# Create an event using full ISO datetimes
curl -X POST http://localhost:8716/api/events \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Team sync",
    "startTime": "2026-06-01T10:00:00.000Z",
    "endTime": "2026-06-01T11:00:00.000Z",
    "color": "blue",
    "location": "Zoom"
  }'