Developer API

The Notedog API

The same on-device HTTPS server that powers browser editing exposes a small REST API under /api/v2. Point your own scripts — or an AI agent — at it over your local network or the tunnel. Your journal stays on your phone; the API just reads and writes the same Markdown files.

Building for an AI agent? You usually don’t need to touch this API directly — the Notedog MCP server wraps it as ready-made tools. This page is the raw contract underneath.

Authentication

Every /api/v2/* request carries a token in the Authorization header. There are two kinds of token, and both are sent the same way:

Authorization: Bearer <token>

Paired browser tokens

When you open the web editor and approve the pairing prompt, the browser receives a short-lived access token (12 hours) plus a refresh token (30 days, rotated on use). This is what the web UI uses; it’s also stored as an HttpOnly cookie.

API keys (for scripts & agents)

For anything that isn’t a browser, mint a dedicated key in the app: open the drawer → API keysCreate key. Keys are long-lived (no expiry) and you can revoke any of them at any time from the same screen.

An API key is a bearer token: anyone holding it has that level of access over your LAN or tunnel. Keep it secret (don’t commit it to a repo), prefer read-only unless you need writes, and revoke it in the app if it leaks. Scope is enforced on the phone — a read-only key simply can’t mutate anything.

Base URL

Entry shape

Most endpoints return entries in this form:

{
  "path": "entries/2026-05-24.md",  // path inside the journal
  "content": "# ...",                // markdown (preview in lists, full when fetched by path)
  "timestamp": 1748044800000,        // last modified, ms since epoch
  "createdAt": 1748000000000         // created, ms since epoch
}

Endpoints

All paths are under /api/v2. Endpoints marked write require a read-write key (a read-only key gets 403).

Entries

Method & pathDescription
GET /entriesList entries (preview content), newest first. Query: q (search), from/to (YYYY-MM-DD), limit (default 50, max 200), cursor. Returns { entries, nextCursor }; nextCursor: null is the last page.
GET /entries/{path}One entry with full content. 404 if missing.
POST /entries writeCreate. Body { path?, content } (blank path uses your filename template). 201 { path }; 409 on collision; 422 on validation failure.
PUT /entries/{path} writeUpdate content, optionally rename. Body { content, newPath? }. 200 { path }; 409 on rename collision.
DELETE /entries/{path} writeDelete. 204 (also if already gone).

When q or from/to are present, results are ranked by relevance (BM25 + a filename-match bonus, ties broken by recency); otherwise newest-first by createdAt.

Directories

Method & pathDescription
GET /directoriesJournal root: { dirs, files }.
GET /directories/{path}A subfolder, same shape. Rejects .. with 400.
POST /directories writeCreate a folder. Body { parent, name } (single segment). 201 { path }; 400/404/409.

Attachments

Method & pathDescription
GET /attachments/{path}Serve an image. Sends ETag/Cache-Control; 304 on a matching If-None-Match.
POST /attachments writeUpload an image (multipart, field file; png/jpg/gif/webp, max 10 MB). 200 { path }.
PUT /attachments/{path} writeOverwrite an existing attachment. 200 { path }; 404 if absent.
DELETE /attachments/{path} writeDelete. 204.

Recents, preferences & journal

Method & pathDescription
GET /journalActive journal: { name } (null if none).
GET /recent-entriesRecently opened entries (MRU order).
POST /recent-entries writeMark an entry opened. Body { path }.
GET /recent-searchesUp to 5 recent keywords.
POST /recent-searches writeTrack a keyword. Body { keyword }.
GET /preferencesEditor preferences: { [key]: string }.
PUT /preferences writeReplace the whole preferences object.
POST /exportStream the journal as a ZIP (application/zip).

Status codes

Examples

Read — search the journal:

curl -H "Authorization: Bearer $NOTEDOG_KEY" \
  "https://your-name.t.notedog.run/api/v2/entries?q=domain%20driven%20design"

Write — create an entry (needs a read-write key):

curl -X POST -H "Authorization: Bearer $NOTEDOG_KEY" \
  -H "Content-Type: application/json" \
  -d '{"content":"# Meeting notes\n..."}' \
  "https://your-name.t.notedog.run/api/v2/entries"

For AI agents, the Notedog MCP server exposes these as tools so you don’t have to wire up HTTP yourself.