trilium-etapi

Use when interacting with a Trilium Notes server via the ETAPI REST API - creating, reading, updating, searching, or deleting notes, branches, attributes, attachments, day/week/month notes; obtaining auth tokens; or scripting Trilium operations from the shell. Triggers on mentions of Trilium, ETAPI, noteId, branchId, or any /etapi/ URL.

Safety Notice

This listing is from the official public ClawHub registry. Review SKILL.md and referenced scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "trilium-etapi" with this command: npx skills add yanickxia/trilium-etapi

Trilium ETAPI

Overview

ETAPI is the external REST API for Trilium Notes (Trilium ≥ 0.50). All requests require token auth. Resources are addressed by 12-char IDs: noteId, branchId, attributeId, attachmentId.

Core concepts:

  • Note — a content unit (HTML/code/file/image/...), identified by noteId
  • Branch — the parent-child relationship between two notes (the same note can be cloned under multiple parents)
  • Attribute — a label or relation attached to a note
  • Attachment — a binary or text payload owned by a note

When to Use

  • Bulk-create or import notes via script (daily notes, inbox, capture)
  • Push content into Trilium from external systems (RSS, email, webhooks)
  • Search/export Trilium content for consumption by other tools
  • Trigger server-side database backups, export subtrees
  • Debug ETAPI integrations (clients like trilium-py / trilium-client just wrap this API)

Do not use for scripts running inside Trilium — use the frontend/backend Script API directly, no HTTP needed.

Setup

All examples below assume:

export TRILIUM_URL="http://localhost:8080"   # no trailing /etapi
export TRILIUM_TOKEN="<generate via Trilium → Options → ETAPI>"

If you only have a password (and the server allows password login), exchange it for a token:

curl -sX POST "$TRILIUM_URL/etapi/auth/login" \
  -H 'Content-Type: application/json' \
  -d '{"password":"YOUR_PASSWORD"}' | jq -r .authToken

Three auth styles (pick one, in the Authorization header):

  1. Authorization: $TRILIUM_TOKEN — raw token (works on every version)
  2. Authorization: Bearer $TRILIUM_TOKEN — Bearer form (v0.93+)
  3. Authorization: Basic $(echo -n "etapi:$TRILIUM_TOKEN" | base64) — Basic auth (v0.56+)

Quick Reference

OperationMethodPath
Health / versionGET/etapi/app-info
Search notesGET/etapi/notes?search=...
Read note metadataGET/etapi/notes/{noteId}
Read note contentGET/etapi/notes/{noteId}/content
Write note contentPUT/etapi/notes/{noteId}/content (text/plain)
Create notePOST/etapi/create-note
Patch note metadataPATCH/etapi/notes/{noteId}
Delete noteDELETE/etapi/notes/{noteId}
Export subtree as ZIPGET/etapi/notes/{noteId}/export?format=html|markdown
Import ZIPPOST/etapi/notes/{noteId}/import
Create / move branchPOST/etapi/branches
Create attributePOST/etapi/attributes
Create attachmentPOST/etapi/attachments
Day note (auto-create)GET/etapi/calendar/days/{YYYY-MM-DD}
InboxGET/etapi/inbox/{YYYY-MM-DD}
Trigger DB backupPUT/etapi/backup/{name}

Full endpoint, parameter, and schema reference: api-reference.md.

Core Patterns (curl + jq)

All snippets below assume TRILIUM_URL and TRILIUM_TOKEN are exported.

1. Health check

curl -s "$TRILIUM_URL/etapi/app-info" -H "Authorization: $TRILIUM_TOKEN" | jq

2. Create a text note

curl -sX POST "$TRILIUM_URL/etapi/create-note" \
  -H "Authorization: $TRILIUM_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "parentNoteId": "root",
    "title": "Hello from ETAPI",
    "type": "text",
    "content": "<p>Created via curl</p>"
  }' | jq '{noteId: .note.noteId, branchId: .branch.branchId}'

Returns NoteWithBranch: the new note plus the branch mounting it.

3. Replace note content

Content lives on a separate endpoint and the body is text/plain even when the content is HTML:

curl -sX PUT "$TRILIUM_URL/etapi/notes/$NOTE_ID/content" \
  -H "Authorization: $TRILIUM_TOKEN" \
  -H 'Content-Type: text/plain' \
  --data-binary @body.html

4. Search

# fulltext + label
curl -sG "$TRILIUM_URL/etapi/notes" \
  -H "Authorization: $TRILIUM_TOKEN" \
  --data-urlencode 'search=tolkien #book' \
  --data-urlencode 'limit=10' | jq '.results[] | {noteId, title}'

Search syntax matches the Trilium UI search bar. Common forms: #tag, #tag=value, note.content *= "...", ~relation.title = "...".

5. Tag a note

curl -sX POST "$TRILIUM_URL/etapi/attributes" \
  -H "Authorization: $TRILIUM_TOKEN" \
  -H 'Content-Type: application/json' \
  -d "{
    \"noteId\": \"$NOTE_ID\",
    \"type\": \"label\",
    \"name\": \"book\",
    \"value\": \"\",
    \"isInheritable\": false
  }"

6. Day note (auto-created on demand)

TODAY=$(date +%F)
curl -s "$TRILIUM_URL/etapi/calendar/days/$TODAY" \
  -H "Authorization: $TRILIUM_TOKEN" | jq -r .noteId

7. Clone a note to another location (branch)

curl -sX POST "$TRILIUM_URL/etapi/branches" \
  -H "Authorization: $TRILIUM_TOKEN" \
  -H 'Content-Type: application/json' \
  -d "{
    \"noteId\": \"$CHILD_ID\",
    \"parentNoteId\": \"$NEW_PARENT_ID\",
    \"prefix\": \"\",
    \"notePosition\": 100,
    \"isExpanded\": false
  }"

8. Export a subtree as ZIP

curl -s "$TRILIUM_URL/etapi/notes/$NOTE_ID/export?format=markdown" \
  -H "Authorization: $TRILIUM_TOKEN" -o subtree.zip
# Whole document: use noteId="root"

9. Trigger a server-side backup

curl -sX PUT "$TRILIUM_URL/etapi/backup/now" \
  -H "Authorization: $TRILIUM_TOKEN"
# Writes to dataDirectory/backup/backup-now.db

Common Pitfalls

  • Don't add a Bearer prefix to Authorization unless you're on v0.93+ and explicitly want Bearer. The raw token form works on every version.
  • PUT /notes/{id}/content body is text/plain (NOT text/html). The OpenAPI spec is explicit on this.
  • PATCH /notes/{id} only patches a subset: title, type, mime, dateCreated, utcDateCreated. Use PUT .../content to change content.
  • PATCH /branches/{id} only patches prefix and notePosition. To re-parent a note you must DELETE the branch and POST a new one.
  • PATCH /attributes/{id}: labels can only patch value and position; relations can only patch position. Anything else means delete + recreate.
  • Deleting the last branch of a note also deletes the note. Watch out when DELETE-ing branches.
  • notePosition defaults to step 10 (10/20/30...). To insert in front, use 5; to push to the end, use a large value like 1000000. After bulk reorders, call POST /refresh-note-ordering/{parentNoteId} so connected clients refresh.
  • EntityId pattern is [a-zA-Z0-9_]{4,32}. root is the special root noteId.
  • Error responses are always {status, code, message}. Branch on the stable code constant (e.g. NOTE_IS_PROTECTED), not on the human-readable message.
  • /auth/login is rate-limited. Too many failures returns 429 and temporarily blacklists the client IP.

Note Types

typeUsemime required?
textRich text (HTML)no
codeSource codeyes (e.g. text/x-python)
fileBinary fileyes
imageImageyes (e.g. image/png)
searchSaved searchno
bookFolder-style containerno
relationMapRelation mapno
renderCustom rendererno

You may also see these on read: noteMap, mermaid, webView, shortcut, doc, contentWidget, launcher.

Workflow: Append to today's day note

A typical inbox / capture flow — append arbitrary text to today's day note:

TODAY=$(date +%F)
NOTE_ID=$(curl -s "$TRILIUM_URL/etapi/calendar/days/$TODAY" \
  -H "Authorization: $TRILIUM_TOKEN" | jq -r .noteId)

OLD=$(curl -s "$TRILIUM_URL/etapi/notes/$NOTE_ID/content" \
  -H "Authorization: $TRILIUM_TOKEN")

NEW="${OLD}<p>$(date +%H:%M) — $1</p>"

curl -sX PUT "$TRILIUM_URL/etapi/notes/$NOTE_ID/content" \
  -H "Authorization: $TRILIUM_TOKEN" \
  -H 'Content-Type: text/plain' \
  --data-binary "$NEW"

When You Need More

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

General

Huo15 Openclaw Enhance

火一五·克劳德·龙虾增强插件 v5.7.8 — 全面适配 openclaw 2026.4.24:peerDep ^4.24 + build/compat 同步到 4.24 + 14 处 api.on 全部去掉 as any 改成 typed hook(hookName 联合类型 + handler 自动推断 Pl...

Registry SourceRecently Updated
General

Content Trend Analyzer

Aggregates and analyzes content trends across platforms to identify hot topics, user intent, content gaps, and generates data-driven article outlines.

Registry SourceRecently Updated
General

Prompt Debugger

Debug prompts that produce unexpected AI outputs — diagnose failure modes, identify ambiguity and conflicting instructions, test variations, compare model re...

Registry SourceRecently Updated
General

Indie Maker News

独行者 Daily - 变现雷达。读对一条新闻,少走一年弯路。每天5分钟,给创业者装上商业雷达。聚焦一人公司、副业、创业变现资讯,智能分类,行动导向。用户下载即能用,无需本地部署!

Registry SourceRecently Updated