TaskNotes HTTP API
The TaskNotes HTTP API provides local HTTP access to tasks, time tracking, pomodoro, calendars, webhooks, and NLP parsing.
Availability
- Desktop only
- Disabled by default
- Started when Obsidian starts and TaskNotes API is enabled
- Bound to loopback (
127.0.0.1) only, not the local network - Browser CORS requests are allowed only from loopback origins such as
localhost,127.0.0.1, and[::1] - Not available on mobile
Enable it in Settings -> TaskNotes -> Integrations -> HTTP API.
Base URL
http://localhost:{PORT}
Default port is 8080.
Authentication
Authentication is optional.
- If
apiAuthTokenis empty, all API requests are accepted. - If
apiAuthTokenis set, sendAuthorization: Bearer <token>. - Set a token for any workflow where local browser pages, scripts, or other desktop apps are not fully trusted.
Example:
curl -H "Authorization: Bearer YOUR_TOKEN" http://localhost:8080/api/health
Response Format
Success:
{
"success": true,
"data": {}
}
Error:
{
"success": false,
"error": "Error message"
}
Endpoint Index
System
GET /api/healthGET /api/docsGET /api/docs/uiPOST /api/nlp/parsePOST /api/nlp/create
Tasks
GET /api/tasksPOST /api/tasksGET /api/tasks/:idPUT /api/tasks/:idDELETE /api/tasks/:idPOST /api/tasks/:id/toggle-statusPOST /api/tasks/:id/archivePOST /api/tasks/:id/complete-instancePOST /api/tasks/:id/materialize-occurrencePOST /api/tasks/queryGET /api/filter-optionsGET /api/stats
Bases
POST /api/bases/default-files/update
Time Tracking
POST /api/tasks/:id/time/startPOST /api/tasks/:id/time/start-with-descriptionPOST /api/tasks/:id/time/stopGET /api/tasks/:id/timeGET /api/time/activeGET /api/time/summary
Pomodoro
POST /api/pomodoro/startPOST /api/pomodoro/stopPOST /api/pomodoro/pausePOST /api/pomodoro/resumeGET /api/pomodoro/statusGET /api/pomodoro/sessionsGET /api/pomodoro/stats
Calendars
GET /api/calendarsGET /api/calendars/googleGET /api/calendars/microsoftGET /api/calendars/subscriptionsGET /api/calendars/events
Webhooks
POST /api/webhooksGET /api/webhooksDELETE /api/webhooks/:idGET /api/webhooks/deliveries
See docs/webhooks.md for event and transform details.
Route Details
Health
GET /api/health
Returns service state plus vault metadata.
curl http://localhost:8080/api/health
Tasks
GET /api/tasks
Basic task listing with pagination only.
Query params:
limit(default50, max200)offset(default0)
Important:
- Filtering params such as
status,priority,tag,project,context,due_before,due_after,overdue,completed,archived, andsortare rejected on this endpoint with HTTP400. - Use
POST /api/tasks/queryfor filtering.
Example:
curl "http://localhost:8080/api/tasks?limit=25&offset=0"
Response fields:
data.tasksdata.paginationwithtotal,offset,limit,hasMoredata.vaultdata.note- Task objects include configured TaskNotes user fields in
customProperties, keyed by their frontmatter property key.
POST /api/tasks
Create one task.
Required:
title
Common optional fields:
details,status,priority,due,scheduledtags,contexts,projectsrecurrence,recurrence_anchor,timeEstimate,remindersblockedBy
blockedBy accepts an array of dependency objects:
uid: link or identifier for the blocking task, such as[[Project setup]]reltype: one ofFINISHTOSTART,FINISHTOFINISH,STARTTOSTART, orSTARTTOFINISHgap: optional ISO 8601 duration, such asP1D
blocking is a read-only reverse relationship in API responses. To make a task block existing tasks, update those existing tasks' blockedBy fields.
curl -X POST http://localhost:8080/api/tasks \
-H "Content-Type: application/json" \
-d '{"title":"Review docs","priority":"high","blockedBy":[{"uid":"[[Draft docs]]","reltype":"FINISHTOSTART"}]}'
Returns HTTP 201 with created task data.
GET /api/tasks/:id
Get one task by path id.
:idmust be URL-encoded task path.- Single-task reads include the task body in
details. - Configured TaskNotes user fields are returned in
customProperties, keyed by their frontmatter property key.
curl "http://localhost:8080/api/tasks/TaskNotes%2FTasks%2FReview%20docs.md"
PUT /api/tasks/:id
Update task with partial payload.
Configured TaskNotes user fields can be updated either by their frontmatter property key or via customProperties.
curl -X PUT "http://localhost:8080/api/tasks/TaskNotes%2FTasks%2FReview%20docs.md" \
-H "Content-Type: application/json" \
-d '{"status":"in-progress"}'
DELETE /api/tasks/:id
Delete task file.
POST /api/tasks/:id/toggle-status
Toggle task status via configured workflow.
POST /api/tasks/:id/archive
Toggle archive state.
POST /api/tasks/:id/complete-instance
Complete recurring instance.
Request body:
- Optional
date(ISO string). If omitted, uses current date context.
When the recurring parent uses materialized occurrence notes, this endpoint completes the matching occurrence note if one exists. If the parent is set to Create next after completion and no matching occurrence note exists yet, TaskNotes creates and completes that occurrence note instead of only recording a virtual complete_instances entry.
POST /api/tasks/:id/materialize-occurrence
Create or return a materialized occurrence note for a recurring task date. This endpoint is idempotent for the same parent and date.
Request body:
- Required
date(ISO date string, for example2026-06-01)
POST /api/tasks/query
Advanced filtering.
Request body is a FilterQuery object. FilterQuery is still the supported advanced query shape for the HTTP API.
The root object is a group with:
type: "group"idconjunction: "and" | "or"children(conditions or groups)
Optional top-level query options:
sortKey,sortDirectiongroupKey,subgroupKey
Example:
{
"type": "group",
"id": "root",
"conjunction": "and",
"children": [
{
"type": "condition",
"id": "c1",
"property": "status",
"operator": "is",
"value": "open"
}
],
"sortKey": "due",
"sortDirection": "asc"
}
Filter tasks by context:
{
"type": "group",
"id": "root",
"conjunction": "and",
"children": [
{
"type": "condition",
"id": "context",
"property": "contexts",
"operator": "contains",
"value": "@office"
}
],
"sortKey": "due",
"sortDirection": "asc"
}
Filter active, unarchived tasks, similar to the default available-task view:
{
"type": "group",
"id": "root",
"conjunction": "and",
"children": [
{
"type": "condition",
"id": "not-archived",
"property": "archived",
"operator": "is-not-checked"
},
{
"type": "condition",
"id": "not-completed",
"property": "status.isCompleted",
"operator": "is-not-checked"
}
],
"sortKey": "due",
"sortDirection": "asc",
"groupKey": "none"
}
Condition fields:
type:"condition"id: any stable string for your clientproperty: a task property, such astitle,status,priority,tags,contexts,projects,blockedBy,blocking,due,scheduled,completedDate,dateCreated,dateModified,archived,hasSubtasks,dependencies.isBlocked,dependencies.isBlocking,timeEstimate,recurrence, orstatus.isCompletedoperator: one ofis,is-not,contains,does-not-contain,is-before,is-after,is-on-or-before,is-on-or-after,is-empty,is-not-empty,is-checked,is-not-checked,is-greater-than,is-less-than,is-greater-than-or-equal, oris-less-than-or-equalvalue: required for comparison operators, omitted for empty/checked operators
For user-defined fields, use property: "user:<fieldId>".
Response:
data.tasksdata.totaldata.filtereddata.vault
GET /api/filter-options
Returns filter options for UI builders.
GET /api/stats
Returns summary counts:
total,completed,active,overdue,archived,withTimeTracking
Bases
POST /api/bases/default-files/update
Overwrite the configured default TaskNotes .base files with templates generated from the current TaskNotes settings. This is the same write operation as Settings -> TaskNotes -> Views & base files -> Update files and replaces manual edits in those configured default files.
curl -X POST http://localhost:8080/api/bases/default-files/update
Response fields:
data.created: default files created because they were missingdata.updated: existing default files overwritten with current templatesdata.skipped: configured default files skipped
Time Tracking
POST /api/tasks/:id/time/start
Starts a new active time entry for that task.
POST /api/tasks/:id/time/start-with-description
Starts time tracking and writes description on the new active entry.
Request body:
{
"description": "Implementation"
}
POST /api/tasks/:id/time/stop
Stops active time entry for that task.
GET /api/tasks/:id/time
Returns per-task time summary and entries.
GET /api/time/active
Returns currently active sessions across tasks.
Important:
- Multiple active sessions can exist across different tasks.
GET /api/time/summary
Returns aggregate time summary.
Query params:
period(for exampletoday,week,month,all)from(ISO date)to(ISO date)
Example:
curl "http://localhost:8080/api/time/summary?period=week"
Pomodoro
POST /api/pomodoro/start
Starts a session.
Optional request fields:
taskId(URL path of task)duration(number)
POST /api/pomodoro/stop
Stops and resets current session.
POST /api/pomodoro/pause
Pauses running session.
POST /api/pomodoro/resume
Resumes paused session.
GET /api/pomodoro/status
Returns current state plus computed totals (totalPomodoros, currentStreak, totalMinutesToday).
GET /api/pomodoro/sessions
Returns history.
Query params:
limitdate(YYYY-MM-DD)
GET /api/pomodoro/stats
Returns stats for today or provided date.
Query params:
date(YYYY-MM-DD)
Calendars
GET /api/calendars
Returns provider connectivity overview and subscription counts.
GET /api/calendars/google
Returns Google provider details.
- If disconnected, returns
{ "connected": false }.
GET /api/calendars/microsoft
Returns Microsoft provider details.
- If disconnected, returns
{ "connected": false }.
GET /api/calendars/subscriptions
Returns ICS subscriptions with runtime fields such as lastFetched and lastError.
GET /api/calendars/events
Returns merged event list from connected providers and ICS subscriptions.
Query params:
start(ISO date/datetime)end(ISO date/datetime)
Response includes:
eventstotalsources(counts by provider)
Webhooks
POST /api/webhooks
Registers webhook.
Required fields:
urlevents(non-empty array)
Optional fields:
idsecretactivetransformFilecorsHeaders
GET /api/webhooks
Lists registered webhooks. Stored secrets are not returned.
DELETE /api/webhooks/:id
Deletes webhook.
GET /api/webhooks/deliveries
Returns last 100 delivery records.
OpenAPI Docs
GET /api/docs
Returns OpenAPI JSON generated from registered controllers.
GET /api/docs/ui
Returns Swagger UI.
Errors
Common status codes:
400invalid request or invalid state401missing/invalid bearer token (when auth token is configured)404missing task/webhook/resource500internal error
Security Notes
Current behavior:
- CORS allows all origins (
*). - Transport is HTTP only (no TLS).
- Node server is started with
server.listen(port)and does not explicitly bind to127.0.0.1.
Practical guidance:
- Set an auth token.
- Treat API port as sensitive and keep it firewalled.
- If you expose this port outside localhost, route through a trusted reverse proxy and TLS.
Troubleshooting
API unavailable
- Confirm API is enabled in settings.
- Confirm Obsidian is running.
- Confirm selected port is free.
- Reload plugin or restart Obsidian after changing API enable/port.
401 Authentication required
- Check token value.
- Check
Bearerprefix. - Remove whitespace around token.
Unexpected task list behavior
If you pass filters to GET /api/tasks, the endpoint returns 400 by design. Use POST /api/tasks/query.