Most "Obsidian REST API" plugins expose the app running on your desktop, which means the automation only works while Obsidian is open on that machine. This one lives on the self-hosted sync server instead: it answers whether your laptop is on or not, because the server holds a synchronised copy of the vault.
Everything it writes lands as Markdown, syncs back to your devices, and is readable without the API ever existing.
What it can address#
Stable IDs from frontmatter, not filenames or titles — so renaming a task does not break your script:
GET /api/ext/v2/workspaces/{ws}/items/TSK-00001
GET /api/ext/v2/workspaces/{ws}/lists/LST-02EFGH
GET /api/ext/v2/workspaces/{ws}/docs/DOC-A1B2C3
Workspaces, Spaces, Folders, Lists, Items, comments, checklist entries, attachments, Docs, Pages, saved Views, every resource's fields, password-guarded secret fields, and raw files in the workspace or the wider vault.
Item collections filter on title, status, priority, tag, ancestry, parent, custom
ID and free text, with cursor pagination up to 200 per page. Add labels=true
and coded values come back resolved — priority: 1 arrives with
"priority": "Urgent" alongside it, so your script does not need a copy of the
configuration.
JSON or Markdown, your choice#
curl "$IT_BASE/workspaces/$IT_WS/items/TSK-00001?format=md" \
-H "Authorization: Bearer $IT_KEY"
Ask for format=md and an Item comes back as complete, public Item Markdown; a
Doc comes back assembled with its ordered page tree. Ask for JSON and you get
structured data with resolved ancestry and a revision number.
Access is off until you turn it on#
Per server object, and Off by default:
| Mode | What it allows |
|---|---|
| Off | Nothing |
| Read-only | Read routes only |
| Full | Reads and writes |
Enabling it mints a dedicated key beginning ITX. — separate from the sync
token, scoped to one object, shown once and stored only as a hash. Secret custom
fields need a second explicit opt-in and the workspace password on every
individual request; the password is per-request, never a session.
Concurrency that does not lose work#
Structured responses carry a rev, and applicable reads an ETag. Send it back
on a mutation:
If-Match: "42"
A stale revision gets 412 REVISION_MISMATCH instead of overwriting whatever
changed in between. Multi-file operations — moving an Item, updating a
relationship on both sides, cascading a delete, promoting a page — are atomic.
Errors are a flat envelope with a machine-readable code:
{ "error": "Item not found", "code": "NOT_FOUND", "details": { "id": "TSK-99999" } }
Tooling you do not have to build#
- An interactive console at
/api-console, served from your own server - OpenAPI 3.1 at
/api/ext/v2/openapi.json— import it into any client or generate a typed SDK - A ready-to-run Bruno collection with every endpoint and placeholder values
The full API guide documents every route, scope and error code.
Honest limits#
- It needs the self-hosted server. There is no cloud endpoint to point at — which is the point, but it does mean setting up sync first.
- The legacy v1 API is gone, answering
410with a pointer to v2. If you find an old snippet online, it will not work. - Single-user. The API has no concept of teams, roles or per-user permissions, because neither does the plugin.