Base URL: http://localhost:8000
GET /api/notesReturns all notes with their metadata and folder structure.
Example:
curl http://localhost:8000/api/notesGET /api/notes/{note_path}Retrieve the content of a specific note.
Example:
curl http://localhost:8000/api/notes/folder/mynote.mdPOST /api/notes/{note_path}
Content-Type: application/json
{
"content": "# My Note\nNote content here..."
}Response:
{
"success": true,
"path": "test.md",
"message": "Note created successfully",
"content": "# My Note\nNote content here..."
}Note: When creating a new note, the on_note_create hook is triggered, allowing plugins to modify the initial content. The response includes the potentially modified content.
Linux/Mac:
curl -X POST http://localhost:8000/api/notes/test.md \
-H "Content-Type: application/json" \
-d '{"content": "# Hello World"}'Windows PowerShell:
curl.exe -X POST http://localhost:8000/api/notes/test.md -H "Content-Type: application/json" -d "{\"content\": \"# Hello World\"}"DELETE /api/notes/{note_path}Example:
curl -X DELETE http://localhost:8000/api/notes/test.mdPOST /api/notes/move
Content-Type: application/json
{
"oldPath": "note.md",
"newPath": "folder/note.md"
}GET /api/media/{media_path}Retrieve a media file (image, audio, video, PDF) with authentication protection.
Example:
curl http://localhost:8000/api/media/folder/_attachments/image-20240417093343.pngSecurity Note: This endpoint requires authentication and validates that:
- The media path is within the notes directory (prevents directory traversal)
- The file exists and is a valid media format
- The requesting user is authenticated (if auth is enabled)
POST /api/upload-media
Content-Type: multipart/form-data
file: <media file>
note_path: <path of note to attach to>Upload a media file to the _attachments directory. Files are automatically organized per-folder and named with timestamps to prevent conflicts.
Supported formats & size limits:
| Type | Formats | Max Size |
|---|---|---|
| Images | JPG, PNG, GIF, WebP | 10 MB |
| Audio | MP3, WAV, OGG, M4A | 50 MB |
| Video | MP4, WebM, MOV, AVI | 100 MB |
| Documents | 20 MB |
Response:
{
"success": true,
"path": "folder/_attachments/media-20240417093343.png",
"filename": "media-20240417093343.png",
"message": "Media uploaded successfully"
}Example (using curl):
curl -X POST http://localhost:8000/api/upload-media \
-F "file=@/path/to/file.mp3" \
-F "note_path=folder/mynote.md"Windows PowerShell:
curl.exe -X POST http://localhost:8000/api/upload-media -F "file=@C:\path\to\video.mp4" -F "note_path=folder/mynote.md"POST /api/media/move
Content-Type: application/json
{
"oldPath": "_attachments/image.png",
"newPath": "folder/_attachments/image.png"
}Move a media file to a different location. Supports drag & drop in the UI.
Response:
{
"success": true,
"message": "Media moved successfully",
"newPath": "folder/_attachments/image.png"
}Notes:
- Media is stored in
_attachmentsfolders relative to the note's location - Filenames are automatically timestamped (e.g.,
media-20240417093343.mp3) - Media appears in the sidebar navigation and can be viewed/deleted directly
- Drag & drop files into the editor automatically uploads and inserts markdown
- All media access requires authentication when security is enabled
POST /api/folders
Content-Type: application/json
{
"path": "Projects/2025"
}DELETE /api/folders/{folder_path}Deletes a folder and all its contents.
Example:
curl -X DELETE http://localhost:8000/api/folders/Projects/ArchivePOST /api/folders/move
Content-Type: application/json
{
"oldPath": "OldFolder",
"newPath": "NewFolder"
}POST /api/folders/rename
Content-Type: application/json
{
"oldPath": "Projects",
"newName": "Work"
}GET /api/search?q={query}Example:
curl "http://localhost:8000/api/search?q=hello"GET /api/themesGET /api/themes/{theme_id}Example:
curl http://localhost:8000/api/themes/darkPlugins can hook into various events in the application lifecycle.
| Hook | Triggered When | Can Modify Data |
|---|---|---|
on_note_create |
New note is created | β Yes (return modified content) |
on_note_save |
Note is being saved | β Yes (return transformed content, or None) |
on_note_load |
Note is loaded | β Yes (return transformed content, or None) |
on_note_delete |
Note is deleted | β No |
on_search |
Search is performed | β No |
on_app_startup |
App starts | β No |
See PLUGINS.md for full documentation on creating plugins.
GET /api/pluginsPOST /api/plugins/{plugin_name}/toggle
Content-Type: application/json
{
"enabled": true
}Linux/Mac:
curl -X POST http://localhost:8000/api/plugins/note_stats/toggle \
-H "Content-Type: application/json" \
-d '{"enabled": true}'Windows PowerShell:
curl.exe -X POST http://localhost:8000/api/plugins/note_stats/toggle -H "Content-Type: application/json" -d "{\"enabled\": true}"GET /api/plugins/note_stats/calculate?content={markdown_content}GET /api/graphReturns the relationship graph between notes with link detection.
Response:
{
"nodes": [
{ "id": "folder/note.md", "label": "note" },
{ "id": "another.md", "label": "another" }
],
"edges": [
{ "source": "folder/note.md", "target": "another.md", "type": "wikilink" }
]
}Link Detection:
- Wikilinks -
[[note]]or[[note|display text]]syntax (Obsidian-style) - Markdown links -
[text](note.md)standard internal links - Edge types -
"wikilink"or"markdown"to distinguish link source
GET /api/configReturns application configuration.
GET /healthReturns system health status.
GET /apiInteractive API documentation with try-it-out functionality (Swagger UI).
GET /api/tags
Returns all tags found in notes with their usage counts.
Response:
{
"tags": {
"python": 5,
"tutorial": 3,
"backend": 2
}
}GET /api/tags/{tag_name}
Returns all notes that have a specific tag.
Response:
{
"tag": "python",
"notes": [
{
"path": "tutorials/python-basics.md",
"name": "python-basics",
"folder": "tutorials",
"tags": ["python", "tutorial"]
}
]
}GET /api/templates
Returns all available note templates from the _templates folder.
Response:
{
"templates": [
{
"name": "meeting-notes",
"path": "_templates/meeting-notes.md",
"modified": "2025-11-26T10:30:00"
},
{
"name": "daily-journal",
"path": "_templates/daily-journal.md",
"modified": "2025-11-26T10:25:00"
}
]
}GET /api/templates/{template_name}
Returns the content of a specific template.
Parameters:
template_name- Template name (without .md extension)
Response:
{
"name": "meeting-notes",
"content": "# Meeting Notes\n\nDate: {{date}}\n..."
}POST /api/templates/create-note
Creates a new note from a template with placeholder replacement.
Request Body:
{
"templateName": "meeting-notes",
"notePath": "meetings/weekly-sync.md"
}Placeholders:
{{date}}- Current date (YYYY-MM-DD){{time}}- Current time (HH:MM:SS){{datetime}}- Current datetime{{timestamp}}- Unix timestamp{{year}}- Current year (YYYY){{month}}- Current month (MM){{day}}- Current day (DD){{title}}- Note name without extension{{folder}}- Parent folder name
Response:
{
"success": true,
"path": "meetings/weekly-sync.md",
"message": "Note created from template successfully",
"content": "# Meeting Notes\n\nDate: 2025-11-26\n..."
}Share notes publicly without requiring authentication.
POST /api/share/{note_path}
Content-Type: application/json
{
"theme": "dracula"
}Creates a share token for the note. The theme is optional (defaults to "light").
Response:
{
"success": true,
"token": "LRFEo86oSVeJ3Gju",
"url": "http://localhost:8000/share/LRFEo86oSVeJ3Gju",
"note_path": "folder/note.md"
}GET /api/share/{note_path}Check if a note is currently shared.
Response:
{
"shared": true,
"token": "LRFEo86oSVeJ3Gju",
"url": "http://localhost:8000/share/LRFEo86oSVeJ3Gju",
"theme": "dracula",
"created": "2026-01-15T10:30:00+00:00"
}DELETE /api/share/{note_path}Removes public access to the note.
GET /api/shared-notesReturns paths of all currently shared notes.
Response:
{
"paths": ["folder/note.md", "another.md"]
}GET /share/{token}Public endpoint - no authentication required. Returns the note as a standalone HTML page with the theme set when sharing was created.
All endpoints return JSON responses:
Success:
{
"success": true,
"data": { ... }
}Error:
{
"detail": "Error message"
}π‘ Tip: Visit /api for interactive Swagger UI documentation where you can try endpoints directly in your browser!