19 KiB
TriliumNext ETAPI Complete API Reference
Overview
ETAPI is TriliumNext's public/external REST API available since Trilium v0.50.
Base URLs:
http://localhost:37740/etapihttp://localhost:8080/etapi
API Version: 1.0.0
License: Apache 2.0
Authentication
All operations require authentication using one of these methods:
1. ETAPI Token Authentication (Recommended)
GET /etapi/app-info
Authorization: <ETAPI_TOKEN>
OR (since v0.93.0):
GET /etapi/app-info
Authorization: Bearer <ETAPI_TOKEN>
2. Basic Authentication (since v0.56)
GET /etapi/app-info
Authorization: Basic <BASE64(username:password)>
Note: Password must be the ETAPI token (NOT your Trilium password).
3. Get Token via API
POST /etapi/auth/login
Content-Type: application/json
{
"password": "your_trilium_password"
}
Response:
{
"authToken": "Bc4bFn0Ffiok_4NpbVCDnFz7B2WU+pdhW8B5Ne3DiR5wXrEyqdjgRIsk="
}
Complete API Endpoints
Authentication
Login
- POST
/auth/login - Description: Get an ETAPI token based on password
- Security: None (public endpoint)
- Request Body:
{ "password": "string" } - Responses:
201: Auth token created429: Client IP blacklisted (too many failed attempts)
Application Information
Get App Info
- GET
/app-info - Description: Get application information
- Response:
{ "appVersion": "0.91.0", "dbVersion": 231, "syncVersion": 25, "buildDate": "2022-02-09T22:52:36+01:00", "buildRevision": "23daaa2387a0655685377f0a541d154aeec2aae8", "dataDirectory": "/home/user/data", "clipperProtocolVersion": "1.0", "utcDateTime": "2022-03-07T21:54:25.277Z" }
Get Metrics
- GET
/etapi/metrics - Description: Get Prometheus-format metrics for monitoring
- Query Parameters:
format:jsonorprometheus(default: prometheus)
- Response: Metrics data including note counts, db stats, etc.
Notes Management
Create Note
- POST
/create-note - Description: Create a note and place it into the note tree
- Request Body:
{ "parentNoteId": "root", "title": "My Note", "type": "text", "mime": "text/html", "content": "<p>Hello World</p>", "notePosition": 10, "prefix": "", "isExpanded": false, "noteId": "customId123", "branchId": "customBranchId", "utcDateCreated": "2021-12-31 19:18:11.930Z", "utcDateModified": "2021-12-31 19:18:11.930Z" } - Required Fields:
parentNoteId,title,type,content - Optional Fields:
notePosition,prefix,isExpanded,noteId,branchId, timestamps - Note Types:
text- Rich text notescode- Code notes (requiresmime)file- File attachments (requiresmime)image- Image notes (requiresmime)search- Saved searchbook- Book/container noterelationMap- Relation maprender- Render notenoteMap- Note mapmermaid- Mermaid diagramswebView- Web viewshortcut- Shortcutdoc- DocumentcontentWidget- Content widgetlauncher- Launchercanvas- Canvas note
- Response:
201withNoteWithBranchobject
Search Notes
- GET
/notes - Description: Search notes using query syntax
- Query Parameters:
search(required): Search query stringancestorNoteId: Search in subtree onlyfastSearch: Boolean for fast search modeincludeArchivedNotes: Include archived notes (default: false)orderBy: Field to order by (e.g.,title,dateModified)orderDirection:ascordesclimit: Maximum results (default: 10)debug: Enable debug info
- Response: Array of note objects
Get Note
- GET
/notes/{noteId} - Description: Get note metadata by ID
- Path Parameters:
noteId: Note ID
- Response: Note object with metadata
Get Note Content
- GET
/notes/{noteId}/content - Description: Get note content (HTML/text for text notes, binary for files/images)
- Path Parameters:
noteId: Note ID
- Response: Note content (content-type varies by note type)
Update Note Content
- PUT
/notes/{noteId}/content - Description: Update note content
- Path Parameters:
noteId: Note ID
- Request Body: Raw content (HTML for text notes, binary for files)
- Response:
204No Content
Update Note Metadata
- PATCH
/notes/{noteId} - Description: Update note metadata (title, type, mime, etc.)
- Path Parameters:
noteId: Note ID
- Request Body:
{ "title": "Updated Title", "type": "text", "mime": "text/html" } - Response:
200with updated note object
Delete Note
- DELETE
/notes/{noteId} - Description: Delete note and all its branches
- Path Parameters:
noteId: Note ID
- Response:
204No Content - Note: Deletes all clones/branches of the note
Export Note
- GET
/notes/{noteId}/export - Description: Export note as ZIP file (with optional subtree)
- Path Parameters:
noteId: Note ID (use "root" to export entire tree)
- Query Parameters:
format:htmlormarkdown/md
- Response: ZIP file download
Branches Management
Branches represent note clones/placements in the tree. A single note can exist in multiple locations via different branches.
Create Branch
- POST
/branches - Description: Create a branch (clone a note to another location)
- Request Body:
{ "noteId": "existingNoteId", "parentNoteId": "targetParentId", "prefix": "Branch Prefix", "notePosition": 10, "isExpanded": false, "branchId": "customBranchId" } - Required Fields:
noteId,parentNoteId - Response:
201with Branch object
Get Branch
- GET
/branches/{branchId} - Description: Get branch by ID
- Path Parameters:
branchId: Branch ID
- Response: Branch object
Update Branch
- PATCH
/branches/{branchId} - Description: Update branch (prefix, notePosition)
- Path Parameters:
branchId: Branch ID
- Request Body:
{ "prefix": "New Prefix", "notePosition": 20, "isExpanded": true } - Response:
200with updated branch - Note: Only
prefix,notePosition, andisExpandedcan be updated. For other properties, delete and recreate.
Set Branch Prefix
- PATCH
/branches/{branchId}/set-prefix - Description: Set branch prefix
- Path Parameters:
branchId: Branch ID
- Request Body:
{ "prefix": "New Prefix" }
Move Branch to Parent
- POST
/branches/{branchId}/set-note-to-parent - Description: Move branch to a different parent
- Path Parameters:
branchId: Branch ID
- Request Body:
{ "parentNoteId": "newParentId" }
Delete Branch
- DELETE
/branches/{branchId} - Description: Delete branch (removes note from this tree location)
- Path Parameters:
branchId: Branch ID
- Response:
204No Content - Note: If this is the last branch of the note, the note itself is deleted
Refresh Note Ordering
- PATCH
/refresh-note-ordering/{parentNoteId} - Description: Push notePosition changes to connected clients
- Path Parameters:
parentNoteId: Parent note ID
- Note: Call this after updating branch notePositions to sync changes to clients
Attributes Management
Attributes include labels (key-value metadata) and relations (links between notes).
Create Attribute
- POST
/attributes - Description: Create an attribute
- Request Body:
{ "noteId": "targetNoteId", "type": "label", "name": "priority", "value": "high", "position": 10, "isInheritable": false, "attributeId": "customAttributeId" } - Attribute Types:
label: Key-value metadatarelation: Link to another note (value is target noteId)
- Required Fields:
noteId,type,name - Optional Fields:
value,position,isInheritable,attributeId - Response:
201with Attribute object
Create Attribute for Note
- POST
/notes/{noteId}/attributes - Description: Create attribute for specific note
- Path Parameters:
noteId: Note ID
- Request Body: Same as Create Attribute (noteId not required)
Get Attribute
- GET
/attributes/{attributeId} - Description: Get attribute by ID
- Path Parameters:
attributeId: Attribute ID
- Response: Attribute object
Get Note Attributes
- GET
/notes/{noteId}/attributes - Description: Get all attributes for a note
- Path Parameters:
noteId: Note ID
- Response: Array of attribute objects
Update Attribute
- PATCH
/attributes/{attributeId} - Description: Update attribute (name, value, position)
- Path Parameters:
attributeId: Attribute ID
- Request Body:
{ "name": "newName", "value": "newValue", "position": 20, "isInheritable": true } - Response:
200with updated attribute
Delete Attribute
- DELETE
/attributes/{attributeId} - Description: Delete attribute
- Path Parameters:
attributeId: Attribute ID
- Response:
204No Content
Attachments Management
Create Attachment
- POST
/attachments - Description: Create attachment for a note
- Request Body: Multipart form data with file
{ "ownerId": "noteId", "role": "image", "mime": "image/png", "title": "Screenshot", "position": 10, "attachmentId": "customAttachmentId" } - Required Fields:
ownerId, file data - Optional Fields:
role,mime,title,position,attachmentId - Response:
201with Attachment object
Create Attachment for Note
- POST
/notes/{noteId}/attachments - Description: Create attachment (alternative endpoint)
- Path Parameters:
noteId: Note ID
- Request Body: Same as Create Attachment (ownerId not required)
Get Attachment
- GET
/attachments/{attachmentId} - Description: Get attachment metadata
- Path Parameters:
attachmentId: Attachment ID
- Response: Attachment object
Get Attachment Content
- GET
/attachments/{attachmentId}/content - Description: Get attachment binary content
- Path Parameters:
attachmentId: Attachment ID
- Response: Binary content with appropriate MIME type
Get Note Attachments
- GET
/notes/{noteId}/attachments - Description: Get all attachments for a note
- Path Parameters:
noteId: Note ID
- Response: Array of attachment objects
Update Attachment Content
- PUT
/attachments/{attachmentId}/content - Description: Update attachment binary content
- Path Parameters:
attachmentId: Attachment ID
- Request Body: Binary file data
- Response:
204No Content
Update Attachment Metadata
- PATCH
/attachments/{attachmentId} - Description: Update attachment metadata
- Path Parameters:
attachmentId: Attachment ID
- Request Body:
{ "title": "New Title", "role": "image", "mime": "image/jpeg", "position": 20 } - Response:
200with updated attachment
Delete Attachment
- DELETE
/attachments/{attachmentId} - Description: Delete attachment
- Path Parameters:
attachmentId: Attachment ID
- Response:
204No Content
Special Purpose Endpoints
Get Inbox Note
- GET
/inbox/{date} - Description: Get or create inbox note for specific date
- Path Parameters:
date: Date in formatYYYY-MM-DD
- Response: Note object
- Behavior:
- Returns fixed inbox note (marked with
#inboxlabel) if configured - Otherwise returns/creates day note in journal for the specified date
- Returns fixed inbox note (marked with
Get Day Note
- GET
/calendar/days/{date} - Description: Get or create day note
- Path Parameters:
date: Date in formatYYYY-MM-DD(e.g.,2022-12-31)
- Response: Note object
- Note: Creates note if it doesn't exist
Get Month Note
- GET
/calendar/months/{month} - Description: Get or create month note
- Path Parameters:
month: Month in formatYYYY-MM(e.g.,2022-12)
- Response: Note object
- Note: Creates note if it doesn't exist
Get Year Note
- GET
/calendar/years/{year} - Description: Get or create year note
- Path Parameters:
year: Year in formatYYYY(e.g.,2022)
- Response: Note object
- Note: Creates note if it doesn't exist
Backup
Create Backup
- PUT
/backup/{backupName} - Description: Create a database backup
- Path Parameters:
backupName: Backup filename (without extension)
- Example:
PUT /backup/nowcreatesbackup-now.db - Response:
204No Content
Data Types and Schemas
Common Field Types
- EntityId: 12-character alphanumeric string (e.g.,
evnnmvHTCgIn) - LocalDateTime:
YYYY-MM-DD HH:mm:ss.SSS±ZZZZ(e.g.,2021-12-31 20:18:11.930+0100) - UtcDateTime:
YYYY-MM-DD HH:mm:ss.SSSZ(e.g.,2021-12-31 19:18:11.930Z)
Note Position
- Normal ordering: 10, 20, 30, 40...
- First position: use value < 10 (e.g., 5)
- Last position: use large value (e.g., 1000000)
- Between existing: use value between their positions
Branch Prefix
Branch-specific title prefix displayed in the tree. Useful when same note appears in multiple locations with slightly different context.
Error Responses
All endpoints may return these error responses:
Standard Error Object
{
"status": 400,
"code": "NOTE_IS_PROTECTED",
"message": "Note 'evnnmvHTCgIn' is protected and cannot be modified through ETAPI"
}
Common HTTP Status Codes
200: Success201: Resource created204: Success (no content)400: Bad request (validation error)401: Unauthorized (invalid token)404: Not found429: Too many requests (rate limited/blacklisted)500: Internal server error
Common Error Codes
NOTE_IS_PROTECTED: Protected note cannot be modifiedINVALID_TOKEN: Invalid or expired ETAPI tokenVALIDATION_ERROR: Request validation failedNOT_FOUND: Resource not foundRATE_LIMITED: Too many requests
Search Query Syntax
The /notes search endpoint supports Trilium's query language:
Basic Search
python # Search in title and content
#todo # Find notes with label "todo"
~project # Find notes with relation "project"
Advanced Operators
note.title =* "meeting" # Title contains "meeting"
note.title %= ".*2022.*" # Regex in title
#priority = "high" # Label with specific value
~template = "someNoteId" # Relation to specific note
#created >= MONTH-1 # Created in last month
note.dateModified >= "2022-01-01" # Modified after date
Combining Queries
#todo AND #urgent # Both labels
#work OR #personal # Either label
#project AND note.title =* "Q1" # Label AND title condition
Hierarchical Queries
note.parents.title = "Work" # Direct parent title
note.ancestors.title = "Archive" # Any ancestor title
note.children.title =* "Chapter" # Direct children
See Trilium Search Documentation for complete syntax.
Rate Limiting
- Failed authentication attempts can result in IP blacklist
- Blacklisted IPs receive
429response - Wait period required before retry
- Use valid tokens to avoid blacklisting
Configuration Notes
Upload Size Limits
- Default: 250MB
- Disable limit: Set
TRILIUM_NO_UPLOAD_LIMIT=true - Custom limit: Set
MAX_ALLOWED_FILE_SIZE_MB=<size>
Network Configuration
ETAPI accessible through:
- Local interface:
http://localhost:8080/etapi - Network interface: Configure reverse proxy (nginx/Apache)
- SSL/TLS: Recommended for production use
Best Practices
- Always use ETAPI tokens (not passwords) for authentication
- Store tokens securely - they provide full access to your Trilium instance
- Use notePosition strategically - leave gaps (10, 20, 30) for easy insertion
- Handle branches carefully - deleting last branch deletes the note
- Check for protected notes - they cannot be modified via ETAPI
- Implement rate limiting in your client to avoid blacklisting
- Use search efficiently - leverage fastSearch for better performance
- Call refresh-note-ordering after bulk branch position updates
- Validate data before submission - reduce error responses
- Handle errors gracefully - check status codes and error messages
Example Workflows
Create a Note with Attributes
# 1. Create note
NOTE_RESPONSE=$(curl -X POST "$SERVER/etapi/create-note" \
-H "Authorization: $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"parentNoteId": "root",
"title": "Project TODO",
"type": "text",
"content": "<p>Task list</p>"
}')
NOTE_ID=$(echo $NOTE_RESPONSE | jq -r '.note.noteId')
# 2. Add label
curl -X POST "$SERVER/etapi/attributes" \
-H "Authorization: $TOKEN" \
-H "Content-Type: application/json" \
-d "{
\"noteId\": \"$NOTE_ID\",
\"type\": \"label\",
\"name\": \"priority\",
\"value\": \"high\"
}"
Clone Note to Multiple Locations
# Clone note to another parent
curl -X POST "$SERVER/etapi/branches" \
-H "Authorization: $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"noteId": "existingNoteId",
"parentNoteId": "anotherParentId",
"prefix": "Reference: "
}'
Daily Journal Entry
# Get or create today's note
TODAY=$(date +%Y-%m-%d)
curl "$SERVER/etapi/calendar/days/$TODAY" \
-H "Authorization: $TOKEN"
Client Libraries
Python
- trilium-py: Full-featured client with extended functionality
- PyTrilium: Lightweight wrapper matching OpenAPI spec
- trilium-alchemy: SQLAlchemy-style SDK with CLI toolkit
Node.js
- trilium-etapi: TypeScript wrapper with type safety
Other Tools
- trilium-mcp-server: Model Context Protocol server for LLMs
- openapi-mcp-generator: Generate MCP servers from OpenAPI specs
Version Compatibility
- ETAPI introduced: Trilium v0.50
- Basic Auth support: v0.56
- Bearer token format: v0.93.0
- TriliumNext fork: Compatible with Trilium API, ongoing development
Check /app-info endpoint for version details of your instance.
Additional Resources
- Official Documentation: https://docs.triliumnotes.org/
- GitHub Repository: https://github.com/TriliumNext/Trilium
- Search Syntax Guide: https://github.com/zadam/trilium/wiki/Search
- Community Resources: https://github.com/Nriver/awesome-trilium
License: Apache 2.0
Maintainer: TriliumNext Community
Contact: https://github.com/TriliumNext/Trilium/discussions