Developers
API guide: search, links & graph
Full-text search with operators, fuzzy title matching, linking and unlinking notes, backlinks, tags and the knowledge graph — each with a working request.
WhereBase URL and keys live in Settings → API keys
Same setup as the notes guide: $NODUM is the base URL,
$KEY the API key, and every endpoint here needs only the read scope
unless marked (write).
Search — GET /vaults/{id}/search
curl -H "Authorization: Bearer $KEY" \
"$NODUM/vaults/$VAULT/search?q=spaced%20repetition&limit=20"
{ "ok": true, "data": { "query": "spaced repetition", "total": 7,
"results": [ { "id": "0198…", "title": "Learning", "path": "Topics/Learning",
"snippet": "…the case for <mark>spaced</mark> <mark>repetition</mark>…",
"rank": 0.61, "created_at": "…", "updated_at": "…" } ] } }
The query language is the app's: path:Folder and file:Name narrow,
tag:#name filters by tag, -word excludes, "a phrase" matches exactly.
sort is relevance (default), updated, created or title;
limit/offset paginate with an honest total.
Fuzzy titles — GET /vaults/{id}/quick-switch?q=lear
What ⌘O uses: cheap fuzzy matching over titles and frontmatter aliases —
[{id, title, path, score, alias?}]. Empty q returns the most recent
notes. Use it to resolve half-remembered names before a precise call.
Link two notes — POST /vaults/{id}/notes/{note_id}/links (write)
curl -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"target": "Topics/Learning"}' \
$NODUM/vaults/$VAULT/notes/$NOTE/links
{ "ok": true, "data": { "from": "0198…", "to": "0198…",
"inserted": "- [[Learning]]", "already_linked": false } }
target is an id, a path, or an exact title. Already linked? Nothing is
written and already_linked is true — safe to retry. context puts the
link in a sentence: {"target": "…", "context": "Follows from {link}."}.
When two notes share a title the API writes the path form ([[Topics/…]])
— and if you say only the ambiguous title, it answers 422 naming a path
rather than guessing.
Unlink — DELETE /vaults/{id}/notes/{note_id}/links?target=… (write)
Links are the [[wikilinks]] in the markdown, so unlinking edits the
markdown: every prose link that unambiguously means the target is spliced
out, and {"removed": n} says how many. Embeds (![[…]]) and links inside
code are content, not connections — they stay. removed: 0 still succeeds.
Reading the connections
GET …/notes/{id}/backlinks— who links here:{"backlinks": [{note_id, title, path, count, snippets: ["…the sentence around the link…"]}]}.GET …/notes/{id}/links— links from here, resolved and unresolved.GET …/notes/{id}/unlinked-mentions— notes that mention this title without linking it: the "you should probably link these" list.
Tags
GET /vaults/{id}/tags—[{name, count}], most used first.GET /vaults/{id}/tags/{name}— notes carrying a tag; nested tags match by prefix, soprojectsalso findsprojects/api.
The graph
GET /vaults/{id}/graph— the whole vault:nodes(notes and unresolvedghost:targets, with degree and tags) andedgesas node-index pairs — the same data the in-app graph draws.GET /vaults/{id}/notes/{note_id}/graph?depth=2— the neighborhood around one note, 1–5 hops.
Ask the vault — POST /vaults/{id}/ai/ask (ai)
curl -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"message": "Summarise what my notes say about spaced repetition."}' \
$NODUM/vaults/$VAULT/ai/ask
Answers with {conversation_id, title, reply, provider, model, actions} —
reply is markdown, actions lists any notes the assistant created or
edited, and conversation_id continues the thread on the next call. Uses
the provider configured in Settings → AI (none configured → 404). The
tool loop can take a while; give your client 120 s. And note the scope's
teeth: the assistant's tools can write, so an ai key can change a vault
even without write.
