Files
narl-workspace/docs/wiki/API.md
T
nvrl 2233fa41a6 scratch: the scratchpad is the inbox, with ways out and a search
A note now leaves the scratchpad by becoming something else: `K` keeps it
as a document, as before; `C` makes it a card where `:card` would put one,
the first line its title; `A` opens `:append` with the document on screen
filled in, Tab completing any other title, and puts the note at its end.

`/api/capture` takes `to: "note"` and `to: "document"` (named as a link
names it), and `note`, the scratch note the text came from, dropped once
the text has landed. Appending keeps the revision before it and indexes
links and media, as a save does.

Migration 0028 adds `scratch_fts`; `GET /api/scratch?q=` searches it, and
`/` lists note hits under "notes" after the cards, Enter lowering the
drawer at the note.

The `c` capture line cycles its target with Tab: a card, a note, or a
timed line in today's entry, which `:today <text>` now writes.
2026-10-22 11:22:55 +02:00

6.2 KiB

API

Everything except the login, the health check and the two share routes requires the session cookie; /api/capture takes a token instead. Media answers Range requests, so a video seeks, sealed or not.

method path purpose
GET /api/health public: up, and the database answers — for a supervisor
POST /api/login, /api/logout session; /api/logout?everywhere=true ends every one
GET /api/me current user
GET /api/sessions every signed-in browser, the one seen last first
DELETE /api/sessions/{id} sign another browser out, and lock the vault
GET/POST /api/spaces the spaces / create one
GET/POST /api/nodes children (?parent=) or search (?q=, ?space=; a file matched by its text has in_text and the words around the match as excerpt, each matched word between U+0002 and U+0003) / create, from a template with template_id
GET/PUT/DELETE /api/nodes/{id} read / update only the fields sent — name, body, created_at, has_board; with base_updated_at, refused with 409 once it was saved since / delete into the trash, subtree and all — or for good, for something already in it
GET/DELETE /api/trash what was deleted, the last first / empty it
DELETE /api/trash/{id} delete one thing in the trash for good
POST /api/trash/{id}/restore back where it was deleted from, or to its space when that folder is gone
GET /api/spaces/{id}/board the lists and cards of one space
GET /api/agenda open cards due within a week or in hand, on every board, whether the diary has today, its entries on_this_day in earlier years, and today in WORKSPACE_TIMEZONE, with its bounds
GET /api/diary/days?month=2026-10 the diary's entries in a month, each with its local day
POST /api/diary/day { day? }: the entry of 2026-10-22, or of today in WORKSPACE_TIMEZONE, started from templates/day when there is none; answers { id, created }
GET /api/diary/around/{id} the entries before and after a diary entry, by date
GET /api/nodes/{id}/templates the templates of the space the node is in
POST /api/capture { text, to: "card" | "diary" | "note" | "document", space?, document?, note? }, with a session or Authorization: Bearer a token; note is a scratch note the text came from, dropped once it has landed
GET/POST /api/tokens the capture tokens / make one, { name }, answered with the token this once
DELETE /api/tokens/{id} remove a capture token
POST /api/spaces/{id}/lists add a list
PUT/DELETE /api/lists/{id} rename / delete a list and its cards
POST /api/lists/{id}/cards add a card
PUT/DELETE /api/cards/{id} update (title, body, due, repeat, checklist, labels, done, link) / delete; finishing a repeating card answers its copy as again
POST /api/cards/{id}/move to another list and place in it; again as above
GET /api/cards?q=… cards whose title, summary or a checklist step matches, open ones first; space keeps it to one board
GET/POST /api/scratch the scratchpad's notes, the one touched last first, or with ?q= those a search finds / a new note { body }
PUT/DELETE /api/scratch/{id} rewrite a note { body } / drop it
POST /api/nodes/{id}/move reparent, and place among the new siblings
POST /api/nodes/move { ids, parent_id }: several into one folder, all or none
POST /api/nodes/{id}/import import a folder or zip (multipart) under this node
POST /api/import import an export at the root: directories become spaces
GET /api/resolve?path= the node behind a slug path, work/notes/monday
GET /api/nodes/{id}/revisions a document's earlier versions, the newest first
GET /api/nodes/{id}/revisions/{rev} one earlier version, with its text
GET /api/nodes/{id}/backlinks the documents that link to this one, with the line each does it on
GET /api/nodes/{id}/cards the cards about this document: its own (node_id) and the ones whose summary links here — also in the node itself as cards
POST/DELETE /api/nodes/{id}/share mint or rotate / revoke a share link
GET /api/export the whole workspace, boards and dates included, as a zip
GET/POST /api/backup Proton Drive mirror: status / run now
POST/DELETE /api/backup/login log the mirror in to Proton, body {"username","password"} / forget its session
POST /api/backup/login/totp, /api/backup/login/captcha the two-factor code {"code"}, or the solved human check {"token"}, a waiting login asked for
GET/POST /api/media list / upload (multipart)
GET/DELETE /api/media/{id} serve (with Range) / delete a file nothing in the tree owns
POST /api/typst {source} of a ```typst block → {svg}, or {error} as typst words it
GET /api/spaces/overview every space with what was last written in it
POST /api/nodes/{id}/files upload files into this folder as file nodes (?encrypt=true seals them)
POST /api/nodes/{id}/inspect what a certificate, key or keystore file holds ({password} opens a protected one)
POST /api/nodes/{id}/encrypt, /decrypt seal a file, or a folder for good — what is in it and what lands later — or take it out
GET/POST/PUT /api/vault status / set the password once / change it
POST /api/vault/unlock, /api/vault/lock open / close the vault
GET/POST /api/ssh-keys the keys that may mount over SFTP / add one
DELETE /api/ssh-keys/{id} remove a key, which ends its mounts
POST /api/share/{token} public: read a shared document, body {"key"}; sets the share's media cookie
GET /api/share/{token}/media/{id} public: media inside a shared document, with that cookie
POST /api/share/{token}/typst public: a typst block the shared document holds, with that cookie