{"openapi":"3.0.3","info":{"title":"cattt notes API","version":"1.0.0","description":"Notes API. Authenticate every /api/v1 request (except /health and this spec) with 'Authorization: Bearer <token>' using a developer access token (generate under ⚙ account in the web app; tokens look like cnt_…). Web sessions use Firebase Auth (Google or email/password). A CLI (`uv tool install cattt-notes`, command `cnotes`) wraps every endpoint with --json output."},"servers":[{"url":"https://notes.cattt.co/api/v1"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer"}},"schemas":{"Note":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"string","description":"Markdown body. [[Title]] links other notes."},"collection_id":{"type":"string","nullable":true},"pinned":{"type":"integer","enum":[0,1]},"archived":{"type":"integer","enum":[0,1]},"favorite":{"type":"integer","enum":[0,1]},"color":{"type":"string","description":"Hex color label or empty"},"share_id":{"type":"string","nullable":true,"description":"Public at /s/{share_id} when set"},"project_id":{"type":"string","nullable":true,"description":"Workspace scope; null = personal"},"trashed_at":{"type":"string","nullable":true},"created_at":{"type":"string"},"updated_at":{"type":"string"},"tags":{"type":"array","items":{"type":"string"}}}},"NotePatch":{"type":"object","properties":{"title":{"type":"string"},"content":{"type":"string"},"collection_id":{"type":"string","nullable":true},"tags":{"type":"array","items":{"type":"string"},"description":"Replaces all tags"},"pinned":{"type":"boolean"},"archived":{"type":"boolean"},"favorite":{"type":"boolean"},"color":{"type":"string"},"project_id":{"type":"string","nullable":true},"if_updated_at":{"type":"string","description":"Optimistic concurrency: apply only if updated_at matches, else 409 with {error, current}"}}},"MindMap":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"content":{"type":"object","properties":{"nodes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"x":{"type":"number"},"y":{"type":"number"}}}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":"string"},"target":{"type":"string"}}}},"viewport":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"zoom":{"type":"number"}}}}},"created_at":{"type":"string"},"updated_at":{"type":"string"}}},"MindMapContent":{"type":"object","properties":{"nodes":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"x":{"type":"number"},"y":{"type":"number"}}}},"edges":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"source":{"type":"string"},"target":{"type":"string"}}}},"viewport":{"type":"object","properties":{"x":{"type":"number"},"y":{"type":"number"},"zoom":{"type":"number"}}}}}}},"paths":{"/health":{"get":{"summary":"Liveness check (no auth)","responses":{"200":{"description":"OK"}}}},"/notes":{"get":{"summary":"List/search notes","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"q","in":"query","description":"Full-text search (FTS5, prefix matching)","schema":{"type":"string"}},{"name":"tag","in":"query","description":"Filter by tag name","schema":{"type":"string"}},{"name":"collection","in":"query","description":"Filter by collection id","schema":{"type":"string"}},{"name":"project","in":"query","description":"Project id; empty string for the personal workspace; omit for all","schema":{"type":"string"}},{"name":"archived","in":"query","description":"true to list archived","schema":{"type":"boolean"}},{"name":"trashed","in":"query","description":"true to list trash","schema":{"type":"boolean"}},{"name":"pinned","in":"query","description":"","schema":{"type":"boolean"}},{"name":"favorite","in":"query","description":"","schema":{"type":"boolean"}},{"name":"limit","in":"query","description":"max 200","schema":{"type":"integer"}},{"name":"offset","in":"query","description":"","schema":{"type":"integer"}},{"name":"sort","in":"query","description":"updated | created | title","schema":{"type":"string"}},{"name":"order","in":"query","description":"asc | desc","schema":{"type":"string"}}]},"post":{"summary":"Create note","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotePatch"}}}}}},"/notes/{id}":{"get":{"summary":"Get note","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"patch":{"summary":"Update note (supports if_updated_at optimistic concurrency)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NotePatch"}}}}},"delete":{"summary":"Trash note (permanent=true to hard-delete)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"permanent","in":"query","description":"","schema":{"type":"boolean"}}]}},"/notes/{id}/restore":{"post":{"summary":"Restore from trash","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/notes/{id}/versions":{"get":{"summary":"List saved versions","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/notes/{id}/versions/{vid}":{"get":{"summary":"Get one version's content","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"vid","in":"path","required":true,"schema":{"type":"string"}}]}},"/notes/{id}/backlinks":{"get":{"summary":"Notes whose content contains [[this note's title]]","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/notes/{id}/share":{"post":{"summary":"Create/return public share link (/s/{share_id})","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"Remove public share link","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/notes/{id}/attachments":{"get":{"summary":"List attachments","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"post":{"summary":"Upload attachment (multipart field 'file', max 10 MB); returns url + markdown snippet","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/attachments/{id}":{"get":{"summary":"Download attachment (public while owning note is shared)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"Delete attachment","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/resolve":{"get":{"summary":"Find note by exact title (case-insensitive)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"title","in":"query","description":"","schema":{"type":"string"}}]}},"/tags":{"get":{"summary":"List tags with counts","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}},"post":{"summary":"Create tag","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"color":{"type":"string"}}}}}}}},"/tags/{id}":{"patch":{"summary":"Rename/recolor tag","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"Delete tag","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/collections":{"get":{"summary":"List collections with counts","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}},"post":{"summary":"Create collection","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"icon":{"type":"string"},"parent_id":{"type":"string"}}}}}}}},"/collections/{id}":{"get":{"summary":"Get collection","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"patch":{"summary":"Update collection","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"Delete collection (notes kept, unfiled)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/saved-searches":{"get":{"summary":"List saved searches","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}},"post":{"summary":"Save a search","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"params":{"type":"object"}}}}}}}},"/saved-searches/{id}":{"delete":{"summary":"Delete saved search","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/trash":{"delete":{"summary":"Empty trash permanently","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}}},"/export":{"get":{"summary":"Full JSON export (notes incl. archived/trashed, tags, collections)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}}},"/export/markdown":{"get":{"summary":"Zip of markdown files with frontmatter","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}}},"/import":{"post":{"summary":"Import notes/collections from a JSON export","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object"}}}}}},"/stats":{"get":{"summary":"Counts of notes/archived/trashed/tags/collections","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}}},"/issues":{"get":{"summary":"List issues (separate entity from notes)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"q","in":"query","description":"Substring match on title/description","schema":{"type":"string"}},{"name":"status","in":"query","description":"backlog | todo | doing | done","schema":{"type":"string"}},{"name":"assignee","in":"query","description":"","schema":{"type":"string"}},{"name":"priority","in":"query","description":"low | med | high | urgent","schema":{"type":"string"}},{"name":"project","in":"query","description":"Project id; '' = personal; omit = all","schema":{"type":"string"}},{"name":"label","in":"query","description":"Filter by label","schema":{"type":"string"}}]},"post":{"summary":"Create issue","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"status":{"type":"string"},"priority":{"type":"string"},"assignee":{"type":"string"},"labels":{"type":"array","items":{"type":"string"}},"project_id":{"type":"string","nullable":true},"due_at":{"type":"string","nullable":true}}}}}}}},"/issues/{id}":{"get":{"summary":"Get issue","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"patch":{"summary":"Update issue (same fields as create, plus board_order and recur: daily|weekly|biweekly|monthly — completing a recurring issue spawns the next occurrence)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"Delete issue permanently","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/issues/{id}/comments":{"get":{"summary":"List comments for an issue","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"post":{"summary":"Add a comment to an issue","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string"}}}}}}}},"/issues/{id}/comments/{commentId}":{"delete":{"summary":"Delete an issue comment","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"}}]}},"/issues/{id}/activity":{"get":{"summary":"List recent issue activity, newest first","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/projects":{"get":{"summary":"List projects with note/issue counts","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}},"post":{"summary":"Create project","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"icon":{"type":"string"}}}}}}}},"/projects/{id}":{"patch":{"summary":"Rename/re-icon project","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"Delete project (contents fall back to personal)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/projects/{id}/share":{"post":{"summary":"Create/return public read-only board link (/b/{share_id})","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"delete":{"summary":"Remove public board link","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/notes/{id}/links":{"get":{"summary":"Outgoing [[wikilinks]]: resolved notes + unresolved titles","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/graph":{"get":{"summary":"Note link graph {nodes, edges} for graph visualization","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"project","in":"query","description":"Scope to a project; '' = personal; omit = all","schema":{"type":"string"}}]}},"/mind-maps":{"get":{"summary":"List standalone mind maps","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}},"post":{"summary":"Create standalone mind map","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"content":{"$ref":"#/components/schemas/MindMapContent"}}}}}}}},"/mind-maps/{id}":{"get":{"summary":"Get standalone mind map","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]},"patch":{"summary":"Update standalone mind map title/content","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string"},"content":{"$ref":"#/components/schemas/MindMapContent"}}}}}}},"delete":{"summary":"Delete standalone mind map","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/webhooks":{"get":{"summary":"List webhooks (delivery status; secrets never returned)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}},"post":{"summary":"Register webhook; response includes signing secret exactly once. Deliveries POST {type:'change',method,path,ts} with X-Notes-Signature = HMAC-SHA256(body, secret)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"}}}}}}}},"/webhooks/{id}":{"delete":{"summary":"Delete webhook","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/tokens":{"get":{"summary":"List developer access tokens (name, prefix, last used — never the value)","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}},"post":{"summary":"Generate a developer token; response includes the plaintext exactly once","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}}}}}}}},"/tokens/{id}":{"delete":{"summary":"Revoke a developer token","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}},"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}]}},"/events":{"get":{"summary":"Server-Sent Events stream: {type:'change',origin} on every mutation, {type:'presence',people} on join/leave. Pass ?name= for presence; send X-Notes-Client on mutations to recognize your own echoes.","security":[{"bearer":[]}],"responses":{"200":{"description":"OK"}}}}}}