{"openapi":"3.2.0","info":{"title":"TodoZen API","version":"v1","contact":{"name":"TodoZen support","email":"support@apercallc.com"},"x-parent-company":"Aperca LLC","description":"Every error response uses one envelope: { error: { code, message, requestId } }. Switch on `code` — it is the stable contract. The full catalog is at /docs#errors, and the whole reference in one markdown file at /llms-full.txt."},"paths":{"/api/v1/tasks":{"get":{"summary":"List tasks, filtered by view/tag, or full-text search","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"cursor","in":"query","description":"Opaque page token from a previous response's nextCursor. Search results (q) and list results use different cursor shapes; a cursor from one is rejected by the other with validation_failed.","schema":{"type":"string"}},{"name":"view","in":"query","description":"One of today, upcoming, all, completed. Defaults to all. today returns open tasks due by the end of today in the caller's timezone, which includes anything already overdue; upcoming starts at tomorrow. all is returned in the user's manual order (see PUT /api/v1/tasks/{id}/position); the other three are ordered by createdAt.","schema":{"type":"string","enum":["today","upcoming","all","completed"]}},{"name":"tag","in":"query","schema":{"type":"string"}},{"name":"q","in":"query","description":"Full-text search over title and notes. Takes over the whole listing — view and tag are ignored when q is set, and results are ranked by relevance rather than recency. Paginated like every other list: follow nextCursor to reach the rest of the matches.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of tasks.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"},"subtasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId","subtasks","progress"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}]}},"nextCursor":{"nullable":true,"type":"string"}},"required":["items","nextCursor"],"additionalProperties":false}}}},"400":{"description":"Malformed cursor, view, or query param.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Create a task","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique key for this logical create. Successful results are retained for 24 hours and safely replayed.","schema":{"type":"string","minLength":1,"maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500},"notes":{"nullable":true,"type":"string","maxLength":20000},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"tags":{"maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":50}},"parentId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"recurrence":{"nullable":true,"type":"string","minLength":1,"maxLength":50,"description":"A repeat rule: 'every day', 'every 2 weeks', 'every monday'."},"location":{"nullable":true,"type":"string","maxLength":500,"description":"A free-text place: '123 Main St, Springfield' or 'the library'."},"assigneeId":{"nullable":true,"type":"string","minLength":1}},"required":["title"],"additionalProperties":false}}}},"responses":{"201":{"description":"The created task.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Idempotency key conflict.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"Due date is in the past, or priority is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/{id}":{"get":{"summary":"Get a single task","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The task, with its subtasks.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"},"subtasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId","subtasks","progress"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"patch":{"summary":"Edit a task (partial update)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"If-Match","in":"header","required":false,"description":"Quoted updatedAt value from the item being changed. A stale value returns 412 instead of overwriting a newer edit.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500},"notes":{"nullable":true,"type":"string","maxLength":20000},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"tags":{"maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":50}},"parentId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"recurrence":{"nullable":true,"type":"string","minLength":1,"maxLength":50,"description":"A repeat rule: 'every day', 'every 2 weeks', 'every monday'."},"location":{"nullable":true,"type":"string","maxLength":500,"description":"A free-text place: '123 Main St, Springfield' or 'the library'."},"assigneeId":{"nullable":true,"type":"string","minLength":1}},"additionalProperties":false}}}},"responses":{"200":{"description":"The updated task.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"412":{"description":"The If-Match version is stale.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"Due date is in the past, or priority is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Soft-delete a task","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"If-Match","in":"header","required":false,"description":"Quoted updatedAt value from the item being changed. A stale value returns 412 instead of overwriting a newer edit.","schema":{"type":"string"}}],"responses":{"200":{"description":"The soft-deleted task.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"412":{"description":"The If-Match version is stale.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/{id}/complete":{"post":{"summary":"Complete a task","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"If-Match","in":"header","required":false,"description":"Quoted updatedAt value from the item being changed. A stale value returns 412 instead of overwriting a newer edit.","schema":{"type":"string"}}],"responses":{"200":{"description":"Completion result.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false},"next":{"nullable":true,"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["item","next"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Task exists but cannot be completed: it is already completed (task_already_completed) or soft-deleted (task_deleted).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"412":{"description":"The If-Match version is stale.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/{id}/auto-tag":{"post":{"summary":"Compatibility no-op for the unavailable auto-tag action","description":"Retained so existing v1 clients and deep integrations do not break. AI-assisted tagging is unavailable: this endpoint never reads task text for AI processing, never contacts an external provider, never retries, and always returns the unchanged task with tagged: false.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The unchanged task with tagged: false.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false},"tagged":{"type":"boolean","enum":[false]}},"required":["item","tagged"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/{id}/reopen":{"post":{"summary":"Reopen a completed task (undo complete)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"If-Match","in":"header","required":false,"description":"Quoted updatedAt value from the item being changed. A stale value returns 412 instead of overwriting a newer edit.","schema":{"type":"string"}}],"responses":{"200":{"description":"The reopened task.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Task exists but cannot be reopened: it was never completed (task_not_completed) or is soft-deleted (task_deleted).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"412":{"description":"The If-Match version is stale.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/{id}/position":{"put":{"summary":"Move a task in the All view's manual order","description":"PUT, not PATCH: the body states the whole answer to 'where is this task?', and sending it twice leaves the same result. `afterId: null` moves it to the top, which is why the field is required. The destination is a neighbouring task rather than an index, since an index only means something against a page the server did not send. Top-level tasks only — a subtask is ordered under its parent (ADR 0029).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"afterId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["afterId"],"additionalProperties":false}}}},"responses":{"200":{"description":"The moved task.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Malformed body.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"The task is a subtask (task_not_reorderable), or afterId names the task being moved (task_move_self_reference).","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/trash":{"get":{"summary":"List soft-deleted tasks, newest deletion first","description":"The trash. Flat rather than nested: a subtask deleted on its own has no live parent to sit under, so every deleted row is listed in its own right and parentId says which is which. Ordered by deletedAt rather than createdAt; the cursor is still an opaque page token from nextCursor.","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of trashed tasks. purgesAt is the earliest instant the retention sweep may hard-delete the row, not a promise that it will happen then.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"},"deletedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"purgesAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"daysUntilPurge":{"type":"number"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId","deletedAt","purgesAt","daysUntilPurge"],"additionalProperties":false}},"nextCursor":{"nullable":true,"type":"string"}},"required":["items","nextCursor"],"additionalProperties":false}}}},"400":{"description":"Malformed cursor.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Empty the trash","description":"Hard-deletes every soft-deleted task at once, without waiting out the 30-day retention window. Irreversible — but everything it touches was already deleted once.","responses":{"200":{"description":"How many rows were removed.","content":{"application/json":{"schema":{"type":"object","properties":{"purged":{"type":"number"}},"required":["purged"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/{id}/purge":{"post":{"summary":"Delete one trashed task forever","description":"Only a task already in the trash can be purged; a live task returns 404, so destroying one always takes two deliberate calls. A live subtask under the purged task is promoted to top level rather than removed with it.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"How many rows were removed — the task plus any of its subtasks that were in the trash with it.","content":{"application/json":{"schema":{"type":"object","properties":{"purged":{"type":"number"}},"required":["purged"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/{id}/restore":{"post":{"summary":"Restore a soft-deleted task (undo delete)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The restored task.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Task doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tasks/{id}/goal":{"put":{"summary":"Attach the task to a goal, or detach it","description":"PUT, not PATCH: the body states what the task's goal is, and sending it twice leaves the same result. `goalId: null` detaches, which is why the field is required — an omitted one would make 'detach' and 'leave alone' the same request.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"goalId":{"nullable":true,"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"required":["goalId"],"additionalProperties":false}}}},"responses":{"200":{"description":"The task's new goal.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"taskId":{"type":"string"},"goalId":{"nullable":true,"type":"string"}},"required":["taskId","goalId"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such task, or no such goal.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The task is soft-deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"The task is a subtask — attach its parent instead.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/goals":{"get":{"summary":"List the workspace's goals","description":"Archived goals are excluded unless `archived` is present as a query param, with any value.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"archived","in":"query","required":false,"description":"Present at any value: include archived goals.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of goals.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}},"nextCursor":{"nullable":true,"type":"string"}},"required":["items","nextCursor"],"additionalProperties":false}}}},"400":{"description":"Malformed cursor.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Create a goal","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique key for this logical create. Successful results are retained for 24 hours and safely replayed.","schema":{"type":"string","minLength":1,"maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500},"notes":{"nullable":true,"type":"string","maxLength":20000},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["title"],"additionalProperties":false}}}},"responses":{"201":{"description":"The created goal.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Idempotency key conflict.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/goals/{id}":{"get":{"summary":"Read one goal, with its derived progress","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The goal.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such goal in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"patch":{"summary":"Update or archive a goal","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"If-Match","in":"header","required":false,"description":"Quoted updatedAt value from the item being changed. A stale value returns 412 instead of overwriting a newer edit.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":500},"notes":{"nullable":true,"type":"string","maxLength":20000},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"archived":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"The updated goal.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such goal in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"412":{"description":"The If-Match version is stale.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Soft-delete a goal","description":"The goal's tasks are not deleted with it — a goal groups tasks, it does not own them.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"If-Match","in":"header","required":false,"description":"Quoted updatedAt value from the item being changed. A stale value returns 412 instead of overwriting a newer edit.","schema":{"type":"string"}}],"responses":{"200":{"description":"The soft-deleted goal.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such goal in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"412":{"description":"The If-Match version is stale.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/goals/{id}/restore":{"post":{"summary":"Restore a soft-deleted goal (undo delete)","description":"Restores the goal row and its grouping of tasks. A goal does not own its tasks, so restoring it does not change task rows.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The restored goal.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such goal in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/habits":{"get":{"summary":"List the workspace's habits","description":"Archived habits are excluded unless `archived` is present as a query param, with any value. Streaks and this week's progress are counted from the caller's own check-offs on every read.","parameters":[{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}},{"name":"archived","in":"query","required":false,"description":"Present at any value: include archived habits.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of habits.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"notes":{"nullable":true,"type":"string"},"schedule":{"type":"string"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"streak":{"type":"object","properties":{"current":{"type":"integer","minimum":0,"maximum":9007199254740991},"longest":{"type":"integer","minimum":0,"maximum":9007199254740991},"unit":{"type":"string","enum":["day","week"]}},"required":["current","longest","unit"],"additionalProperties":false},"week":{"type":"object","properties":{"done":{"type":"integer","minimum":0,"maximum":9007199254740991},"expected":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["done","expected"],"additionalProperties":false},"doneToday":{"type":"boolean"},"recentDates":{"type":"array","items":{"type":"string"}}},"required":["id","name","notes","schedule","archivedAt","createdAt","updatedAt","streak","week","doneToday","recentDates"],"additionalProperties":false}},"nextCursor":{"nullable":true,"type":"string"}},"required":["items","nextCursor"],"additionalProperties":false}}}},"400":{"description":"Malformed cursor.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Create a habit","description":"`schedule` accepts `every day`, a list of named weekdays (`every monday and thursday`) and a weekly target (`once a week` or `3 times a week`). `weekly`, `every week`, and `twice a week` are accepted shorthands. It is stored in one canonical spelling, so what you read back may not be what you sent.","parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"A unique key for this logical create. Successful results are retained for 24 hours and safely replayed.","schema":{"type":"string","minLength":1,"maxLength":200}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"notes":{"nullable":true,"type":"string","maxLength":20000},"schedule":{"type":"string","minLength":1,"maxLength":120}},"required":["name","schedule"],"additionalProperties":false}}}},"responses":{"201":{"description":"The created habit.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"notes":{"nullable":true,"type":"string"},"schedule":{"type":"string"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"streak":{"type":"object","properties":{"current":{"type":"integer","minimum":0,"maximum":9007199254740991},"longest":{"type":"integer","minimum":0,"maximum":9007199254740991},"unit":{"type":"string","enum":["day","week"]}},"required":["current","longest","unit"],"additionalProperties":false},"week":{"type":"object","properties":{"done":{"type":"integer","minimum":0,"maximum":9007199254740991},"expected":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["done","expected"],"additionalProperties":false},"doneToday":{"type":"boolean"},"recentDates":{"type":"array","items":{"type":"string"}}},"required":["id","name","notes","schedule","archivedAt","createdAt","updatedAt","streak","week","doneToday","recentDates"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"Idempotency key conflict.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"`habit_invalid_schedule` — the words are well-formed but are not a schedule.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/habits/{id}":{"get":{"summary":"Read one habit, with its streak and this week's progress","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The habit.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"notes":{"nullable":true,"type":"string"},"schedule":{"type":"string"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"streak":{"type":"object","properties":{"current":{"type":"integer","minimum":0,"maximum":9007199254740991},"longest":{"type":"integer","minimum":0,"maximum":9007199254740991},"unit":{"type":"string","enum":["day","week"]}},"required":["current","longest","unit"],"additionalProperties":false},"week":{"type":"object","properties":{"done":{"type":"integer","minimum":0,"maximum":9007199254740991},"expected":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["done","expected"],"additionalProperties":false},"doneToday":{"type":"boolean"},"recentDates":{"type":"array","items":{"type":"string"}}},"required":["id","name","notes","schedule","archivedAt","createdAt","updatedAt","streak","week","doneToday","recentDates"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such habit in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"patch":{"summary":"Update or archive a habit","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"If-Match","in":"header","required":false,"description":"Quoted updatedAt value from the item being changed. A stale value returns 412 instead of overwriting a newer edit.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":200},"notes":{"nullable":true,"type":"string","maxLength":20000},"schedule":{"type":"string","minLength":1,"maxLength":120},"archived":{"type":"boolean"}},"additionalProperties":false}}}},"responses":{"200":{"description":"The updated habit.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"notes":{"nullable":true,"type":"string"},"schedule":{"type":"string"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"streak":{"type":"object","properties":{"current":{"type":"integer","minimum":0,"maximum":9007199254740991},"longest":{"type":"integer","minimum":0,"maximum":9007199254740991},"unit":{"type":"string","enum":["day","week"]}},"required":["current","longest","unit"],"additionalProperties":false},"week":{"type":"object","properties":{"done":{"type":"integer","minimum":0,"maximum":9007199254740991},"expected":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["done","expected"],"additionalProperties":false},"doneToday":{"type":"boolean"},"recentDates":{"type":"array","items":{"type":"string"}}},"required":["id","name","notes","schedule","archivedAt","createdAt","updatedAt","streak","week","doneToday","recentDates"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such habit in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"412":{"description":"The If-Match version is stale.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"The schedule is not one this app reads.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Soft-delete a habit","description":"The habit's history goes with it — unlike a goal's tasks, a check-off means nothing without the habit it belongs to.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"If-Match","in":"header","required":false,"description":"Quoted updatedAt value from the item being changed. A stale value returns 412 instead of overwriting a newer edit.","schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted."},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such habit in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"412":{"description":"The If-Match version is stale.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/habits/{id}/restore":{"post":{"summary":"Restore a soft-deleted habit (undo delete)","description":"Restores the habit and its existing check-off history. A second restore, or an id outside this workspace, returns 404.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The restored habit.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"notes":{"nullable":true,"type":"string"},"schedule":{"type":"string"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"streak":{"type":"object","properties":{"current":{"type":"integer","minimum":0,"maximum":9007199254740991},"longest":{"type":"integer","minimum":0,"maximum":9007199254740991},"unit":{"type":"string","enum":["day","week"]}},"required":["current","longest","unit"],"additionalProperties":false},"week":{"type":"object","properties":{"done":{"type":"integer","minimum":0,"maximum":9007199254740991},"expected":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["done","expected"],"additionalProperties":false},"doneToday":{"type":"boolean"},"recentDates":{"type":"array","items":{"type":"string"}}},"required":["id","name","notes","schedule","archivedAt","createdAt","updatedAt","streak","week","doneToday","recentDates"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such habit in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/habits/{id}/entries":{"put":{"summary":"Check a day off, or un-check it","description":"States what the day should be rather than adding an event: sending it twice leaves one row, and `done: false` removes it, so a retry is always safe. `date` defaults to today in the account's timezone and may not be in the future.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},"done":{"default":true,"type":"boolean"},"note":{"nullable":true,"type":"string","maxLength":2000}},"required":["done"],"additionalProperties":false}}}},"responses":{"200":{"description":"The habit, with its updated streak.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"notes":{"nullable":true,"type":"string"},"schedule":{"type":"string"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"streak":{"type":"object","properties":{"current":{"type":"integer","minimum":0,"maximum":9007199254740991},"longest":{"type":"integer","minimum":0,"maximum":9007199254740991},"unit":{"type":"string","enum":["day","week"]}},"required":["current","longest","unit"],"additionalProperties":false},"week":{"type":"object","properties":{"done":{"type":"integer","minimum":0,"maximum":9007199254740991},"expected":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["done","expected"],"additionalProperties":false},"doneToday":{"type":"boolean"},"recentDates":{"type":"array","items":{"type":"string"}}},"required":["id","name","notes","schedule","archivedAt","createdAt","updatedAt","streak","week","doneToday","recentDates"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such habit in this workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"That day has not happened yet.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/insights":{"get":{"summary":"Streaks, counts and trends over a window of days","description":"Per-day series are gap-filled: a day with nothing in it is a zero rather than a missing point, so a chart drawn from this shows the real shape. Task days are grouped in the account's own timezone; journal and habit days already are one. `completedChangePercent` is null when the previous window was empty, because a percentage against zero says nothing.","parameters":[{"name":"days","in":"query","required":false,"description":"One of 7, 30, 90. Defaults to 30.","schema":{"type":"integer","enum":[7,30,90]}}],"responses":{"200":{"description":"The window's numbers.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"range":{"type":"object","properties":{"from":{"type":"string"},"to":{"type":"string"},"days":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["from","to","days"],"additionalProperties":false},"tasks":{"type":"object","properties":{"completedPerDay":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"count":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["date","count"],"additionalProperties":false}},"completedTotal":{"type":"integer","minimum":0,"maximum":9007199254740991},"completedChangePercent":{"nullable":true,"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdTotal":{"type":"integer","minimum":0,"maximum":9007199254740991},"openNow":{"type":"integer","minimum":0,"maximum":9007199254740991},"overdueNow":{"type":"integer","minimum":0,"maximum":9007199254740991},"busiestDay":{"nullable":true,"type":"object","properties":{"date":{"type":"string"},"count":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["date","count"],"additionalProperties":false},"perDay":{"type":"number"}},"required":["completedPerDay","completedTotal","completedChangePercent","createdTotal","openNow","overdueNow","busiestDay","perDay"],"additionalProperties":false},"journal":{"type":"object","properties":{"entriesPerDay":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"count":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["date","count"],"additionalProperties":false}},"entriesTotal":{"type":"integer","minimum":0,"maximum":9007199254740991},"streak":{"type":"object","properties":{"current":{"type":"integer","minimum":0,"maximum":9007199254740991},"longest":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["current","longest"],"additionalProperties":false},"moods":{"type":"array","items":{"type":"object","properties":{"mood":{"type":"string"},"count":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["mood","count"],"additionalProperties":false}}},"required":["entriesPerDay","entriesTotal","streak","moods"],"additionalProperties":false},"habits":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"schedule":{"type":"string"},"streak":{"type":"object","properties":{"current":{"type":"integer","minimum":0,"maximum":9007199254740991},"longest":{"type":"integer","minimum":0,"maximum":9007199254740991},"unit":{"type":"string","enum":["day","week"]}},"required":["current","longest","unit"],"additionalProperties":false},"week":{"type":"object","properties":{"done":{"type":"integer","minimum":0,"maximum":9007199254740991},"expected":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["done","expected"],"additionalProperties":false},"completionPercent":{"type":"integer","minimum":0,"maximum":100}},"required":["id","name","schedule","streak","week","completionPercent"],"additionalProperties":false}}},"required":["range","tasks","journal","habits"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"`days` is not one of the offered windows.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/journal/streak":{"get":{"summary":"How many days in a row the account has journalled","description":"Its own endpoint rather than a field on the journal listing: a streak is a fact about the whole history, and folding it in would recompute it for every page of a browse. Writing today is not required to keep a streak alive — it breaks only once a whole day has passed with nothing written.","responses":{"200":{"description":"The current and longest run.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"current":{"type":"number"},"longest":{"type":"number"},"today":{"type":"string"}},"required":["current","longest","today"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/journal":{"get":{"summary":"Browse journal entries by date range (most recent first)","parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"cursor","in":"query","schema":{"type":"string"}},{"name":"from","in":"query","description":"YYYY-MM-DD, inclusive.","schema":{"type":"string"}},{"name":"to","in":"query","description":"YYYY-MM-DD, inclusive.","schema":{"type":"string"}},{"name":"pinned","in":"query","description":"Present at any value: only entries marked worth coming back to.","schema":{"type":"string"}},{"name":"tag","in":"query","description":"Only entries carrying this tag. Matched case-insensitively.","schema":{"type":"string"}}],"responses":{"200":{"description":"A page of journal entries.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false}},"nextCursor":{"nullable":true,"type":"string"}},"required":["items","nextCursor"],"additionalProperties":false}}}},"400":{"description":"Malformed cursor, from, or to.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/journal/today":{"get":{"summary":"Get today's journal entry (in the caller's timezone)","responses":{"200":{"description":"Today's entry, or item: null if nothing has been saved yet today.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"nullable":true,"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false},"date":{"type":"string"},"prompt":{"type":"string"}},"required":["item","date","prompt"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"put":{"summary":"Upsert today's journal entry","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","maxLength":50000},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":50}},"pinned":{"type":"boolean"}},"required":["body"],"additionalProperties":false}}}},"responses":{"200":{"description":"The saved entry.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"Body too long, or mood is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/journal/{date}":{"get":{"summary":"Get the entry for a specific date","parameters":[{"name":"date","in":"path","required":true,"description":"YYYY-MM-DD","schema":{"type":"string"}}],"responses":{"200":{"description":"The entry for that date, or item: null if none exists.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"nullable":true,"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"date is not YYYY-MM-DD.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"put":{"summary":"Upsert an entry for today or an earlier date","description":"Backfill a missed day or revise an existing entry. Future dates are rejected.","parameters":[{"name":"date","in":"path","required":true,"description":"A real YYYY-MM-DD day, no later than today.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","maxLength":50000},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"maxItems":50,"type":"array","items":{"type":"string","minLength":1,"maxLength":50}},"pinned":{"type":"boolean"}},"required":["body"],"additionalProperties":false}}}},"responses":{"200":{"description":"The saved entry.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Date or request body is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"Date is in the future, body is too long, or mood is invalid.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Soft-delete the entry for a specific date","parameters":[{"name":"date","in":"path","required":true,"description":"YYYY-MM-DD","schema":{"type":"string"}}],"responses":{"204":{"description":"Entry deleted."},"400":{"description":"date is not YYYY-MM-DD.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Entry doesn't exist, is already deleted, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"patch":{"summary":"Restore a soft-deleted entry (undo delete)","parameters":[{"name":"date","in":"path","required":true,"description":"YYYY-MM-DD","schema":{"type":"string"}}],"responses":{"204":{"description":"Entry restored."},"400":{"description":"date is not YYYY-MM-DD.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Entry doesn't exist, is already live, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/journal/{date}/auto-tag":{"post":{"summary":"Compatibility no-op for the unavailable auto-tag action","description":"Retained so existing v1 clients and deep integrations do not break. AI-assisted tagging is unavailable: this endpoint never reads journal text for AI processing, never contacts an external provider, never retries, and always returns the unchanged entry with tagged: false.","parameters":[{"name":"date","in":"path","required":true,"description":"YYYY-MM-DD","schema":{"type":"string"}}],"responses":{"200":{"description":"The unchanged entry with tagged: false.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false},"tagged":{"type":"boolean","enum":[false]}},"required":["item","tagged"],"additionalProperties":false}}}},"400":{"description":"date is not YYYY-MM-DD.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The active workspace is shared. Journals are available only in the personal workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No entry exists for that date.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tags":{"get":{"summary":"List the workspace's tags","responses":{"200":{"description":"Every tag in the workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","name","createdAt"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Create a tag (find-or-create by normalized name)","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":50}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"The tag (created, or the existing one with that name).","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","name","createdAt"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/tags/{id}":{"delete":{"summary":"Delete a tag (removes it from every task that had it)","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Deleted."},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"Tag doesn't exist, or belongs to another workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/search":{"get":{"summary":"Search tasks, goals, habits and personal journal entries, ranked","parameters":[{"name":"q","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}}],"responses":{"200":{"description":"Ranked results across tasks, goals and habits; personal workspaces also receive journal results.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["task"]},"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["kind","item"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","enum":["goal"]},"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}},"required":["kind","item"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","enum":["journal"]},"item":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["kind","item"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","enum":["habit"]},"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"schedule":{"type":"string"}},"required":["id","name","schedule"],"additionalProperties":false}},"required":["kind","item"],"additionalProperties":false}]}}},"required":["items"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/api-keys":{"get":{"summary":"List the caller's API keys","description":"Revoked keys are archived automatically, preserving when access stopped without cluttering the default list. Pass `?archived=1` to include archived keys. Behind a real session only: an API key cannot be used to list or mint other keys (ADR 0019).","parameters":[{"in":"query","name":"archived","required":false,"description":"Present at any value: include archived keys.","schema":{"type":"string"}}],"responses":{"200":{"description":"Every key this account has issued.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write"]}},"lastUsedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"revokedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","name","prefix","scopes","lastUsedAt","expiresAt","revokedAt","archivedAt","createdAt"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Presented an API key instead of a session — this route requires a signed-in session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Issue a new API key","description":"The plaintext token is returned exactly once, in this response, and cannot be recovered afterward — nothing stores it. Losing it means issuing a new key. Every new key receives both read and write access.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"The created key, plus its one-time token.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write"]}},"lastUsedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"revokedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","name","prefix","scopes","lastUsedAt","expiresAt","revokedAt","archivedAt","createdAt"],"additionalProperties":false},"token":{"type":"string"}},"required":["item","token"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Presented an API key instead of a session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/api-keys/{id}":{"delete":{"summary":"Revoke an API key","description":"Sets revokedAt and archives the row rather than deleting it, so the time access stopped remains available in archived history.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The revoked key.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"prefix":{"type":"string"},"scopes":{"type":"array","items":{"type":"string","enum":["read","write"]}},"lastUsedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"revokedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","name","prefix","scopes","lastUsedAt","expiresAt","revokedAt","archivedAt","createdAt"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Presented an API key instead of a session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such key for this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/import":{"post":{"summary":"Import a previously exported workspace document","description":"Additive only — nothing is ever deleted by an import. The one exception the file can collide on is a journal day that already has an entry, decided by `?mode`: `skip-existing` (the default) keeps what is already there; `merge` overwrites it with the file's version. The whole import is one transaction, so a malformed row leaves the workspace exactly as it was.","parameters":[{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["skip-existing","merge"],"default":"skip-existing"}}],"requestBody":{"required":true,"description":"A document in the shape docs/api/export.md describes.","content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"What landed.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"counts":{"type":"object","properties":{"tasks":{"type":"number"},"goals":{"type":"number"},"journalEntries":{"type":"number"},"habits":{"type":"number"},"tags":{"type":"number"},"skipped":{"type":"number"}},"required":["tasks","goals","journalEntries","habits","tags","skipped"],"additionalProperties":false}},"required":["counts"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body is not a JSON object.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"413":{"description":"Import document exceeds 10 MiB.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"Missing or unsupported format version, or the document failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/export":{"get":{"summary":"Download the caller's full workspace data as JSON","description":"Streams (Transfer-Encoding: chunked) rather than buffering — see docs/api/export.md. Delivered as a file download (Content-Disposition: attachment), rate-limited to 5/hour.","responses":{"200":{"description":"The export.","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":"number"},"exportedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"preferences":{"type":"object","properties":{"theme":{"type":"string"},"themeName":{"type":"string"},"timezone":{"type":"string"},"webWalkthroughVersion":{"type":"integer","minimum":0,"maximum":9007199254740991},"soundEnabled":{"type":"boolean"},"locationSuggestionsEnabled":{"type":"boolean","description":"Whether the task location field calls the geocoding suggestion endpoint (proxied to Photon, an open-source third party). On by default."},"autoTaggingEnabled":{"type":"boolean","enum":[false],"description":"Deprecated compatibility field. AI-assisted tagging is unavailable, so responses always return false."},"taskView":{"type":"string","enum":["today","upcoming","all","completed"]},"taskSort":{"type":"string","enum":["default","due","priority","newest","title"]},"features":{"type":"object","properties":{"habits":{"type":"boolean"},"dashboard":{"type":"boolean"},"themes":{"type":"boolean"},"sharing":{"type":"boolean"},"notifications":{"type":"boolean"}},"required":["habits","dashboard","themes","sharing","notifications"],"additionalProperties":false},"notifications":{"type":"object","properties":{"inApp":{"type":"boolean"},"email":{"type":"boolean"},"push":{"type":"boolean"},"quietHoursStart":{"type":"integer","minimum":0,"maximum":23},"quietHoursEnd":{"type":"integer","minimum":0,"maximum":23},"dailyEmailCap":{"type":"integer","minimum":0,"maximum":100},"habitReminderHour":{"type":"integer","minimum":0,"maximum":23}},"required":["inApp","email","push","quietHoursStart","quietHoursEnd","dailyEmailCap","habitReminderHour"],"additionalProperties":false}},"required":["theme","themeName","timezone","webWalkthroughVersion","soundEnabled","locationSuggestionsEnabled","autoTaggingEnabled","taskView","taskSort","features","notifications"],"additionalProperties":false},"tags":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","name","createdAt"],"additionalProperties":false}},"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location"],"additionalProperties":false}},"goals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}},"journalEntries":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false}},"habits":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"notes":{"nullable":true,"type":"string"},"schedule":{"type":"string"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"entries":{"type":"array","items":{"type":"object","properties":{"date":{"type":"string"},"note":{"nullable":true,"type":"string"}},"required":["date","note"],"additionalProperties":false}}},"required":["id","name","notes","schedule","archivedAt","createdAt","updatedAt","entries"],"additionalProperties":false}}},"required":["version","exportedAt","preferences","tags","tasks","goals","journalEntries","habits"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/notifications":{"get":{"summary":"List the caller's notifications","description":"Newest first, cursor-paginated. `?unread=true` narrows to the ones not yet read. The unread count comes back with the list so opening the bell is one request rather than two — it counts every unread notification, not only this page's.","parameters":[{"name":"unread","in":"query","required":false,"schema":{"type":"string","enum":["true"]}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer"}},{"name":"cursor","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"A page of notifications, with the unread count.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string","enum":["task_due","task_assigned","record_shared","workspace_invitation","habit_reminder"]},"workspaceId":{"nullable":true,"type":"string"},"title":{"type":"string"},"body":{"nullable":true,"type":"string"},"href":{"nullable":true,"type":"string"},"readAt":{"nullable":true,"type":"string"},"createdAt":{"type":"string"}},"required":["id","kind","workspaceId","title","body","href","readAt","createdAt"],"additionalProperties":false}},"nextCursor":{"nullable":true,"type":"string"},"unreadCount":{"type":"number"}},"required":["items","nextCursor","unreadCount"],"additionalProperties":false}}}},"400":{"description":"The cursor is not a valid cursor.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"patch":{"summary":"Mark notifications read","description":"With an `id`, marks that one; with no body field, marks every unread notification. Idempotent — `readAt` is only written where it is still null, so marking something twice does not move the moment it was read, and an id that matches nothing answers 200 with `updated: 0` rather than 404.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"}},"additionalProperties":false}}}},"responses":{"200":{"description":"How many rows changed, and the new unread count.","content":{"application/json":{"schema":{"type":"object","properties":{"updated":{"type":"number"},"unreadCount":{"type":"number"}},"required":["updated","unreadCount"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/push/subscriptions":{"post":{"tags":["Notifications"],"summary":"Register this browser for push notifications","description":"Stores what `PushManager.subscribe()` returned. Keyed on the endpoint, so a browser that re-subscribes updates its row instead of leaving a dead one behind. Answers 201 whether it created or refreshed — 'you were already registered' is not information a client can use. A deployment with no VAPID keys answers 503: it could store the device but could never reach it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"type":"string","maxLength":2048},"keys":{"type":"object","properties":{"p256dh":{"type":"string","minLength":80,"maxLength":100},"auth":{"type":"string","minLength":16,"maxLength":32}},"required":["p256dh","auth"],"additionalProperties":false},"userAgent":{"type":"string","maxLength":300}},"required":["endpoint","keys"],"additionalProperties":false}}}},"responses":{"201":{"description":"Registered."},"400":{"description":"The subscription body is not valid.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"Push is not configured on this server.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"tags":["Notifications"],"summary":"Forget this browser","description":"Scoped to the caller: an endpoint is not a secret — it travels to a push service on every send — so deleting by endpoint alone would let anyone who learned one unsubscribe somebody else's device. Answers 204 whether or not a row went, because reporting 'there was nothing there' would answer whether a given endpoint is registered to the caller.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"endpoint":{"type":"string","maxLength":2048}},"required":["endpoint"],"additionalProperties":false}}}},"responses":{"204":{"description":"Forgotten."},"400":{"description":"The body is not valid.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/account/avatar/upload-url":{"post":{"summary":"Ask for a URL that authorizes one picture upload","description":"The bytes go straight from the client to the object store and never pass through this app. `content-type` and `content-length` are signed into the URL, so it authorizes one object of exactly that type and size — send `requiredHeaders` back verbatim on the PUT or the signature will not match. The key is chosen server-side; a client-chosen key would be a client-chosen path. The URL expires in five minutes.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentType":{"type":"string","enum":["image/webp","image/jpeg","image/png"]},"contentLength":{"type":"integer","minimum":1,"maximum":2097152}},"required":["contentType","contentLength"],"additionalProperties":false}}}},"responses":{"200":{"description":"Where to upload, and what to send with it.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"uploadUrl":{"type":"string"},"key":{"type":"string"},"publicUrl":{"type":"string"},"requiredHeaders":{"type":"object","additionalProperties":{"type":"string"}},"expiresInSeconds":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["uploadUrl","key","publicUrl","requiredHeaders","expiresInSeconds"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"No object store is configured here.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/account/avatar":{"put":{"summary":"Confirm an uploaded picture","description":"The app never sees the upload, so this is the moment it learns one happened. The key is checked against the caller rather than trusted.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","minLength":1,"maxLength":300}},"required":["key"],"additionalProperties":false}}}},"responses":{"200":{"description":"The picture's public URL.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"image":{"type":"string"}},"required":["image"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"That key was not issued to this account.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"503":{"description":"No object store is configured here.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Remove the picture, and the object behind it","responses":{"204":{"description":"Removed."},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/account":{"delete":{"summary":"Hard-delete the caller's account and everything they own","description":"Irreversible. Requires { confirm: \"DELETE\" } as a server-side safety net beyond the UI's own typed confirmation.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"string","enum":["DELETE"]}},"required":["confirm"],"additionalProperties":false}}}},"responses":{"204":{"description":"Deleted."},"400":{"description":"confirm must be exactly \"DELETE\".","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/onboarding/sample-content":{"get":{"summary":"Check whether the workspace currently has sample content","responses":{"200":{"description":"Whether sample content is present.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"present":{"type":"boolean"}},"required":["present"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key, or sample content is unavailable in a shared workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Seed optional onboarding tasks with immutable provenance","description":"Creates a few optional onboarding tasks. Each task is identified by an immutable `onboardingSampleKey`; the visible `sample` tag is teaching content only and is not used to identify or remove rows. Edits, retagging, and user-created descendants are preserved.","responses":{"201":{"description":"Sample content created.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"present":{"type":"boolean"}},"required":["present"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key, or sample content is unavailable in a shared workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Remove onboarding tasks by immutable provenance","description":"Deletes only tasks created with an `onboardingSampleKey` in this workspace. It does not inspect the visible `sample` tag, so user-created #sample tasks and journal tags are preserved. User-created descendants are promoted before sample parents are removed. Repeating this action is safe.","responses":{"204":{"description":"Removed."},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key, or sample content is unavailable in a shared workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/preferences":{"get":{"summary":"Get the caller's preferences","responses":{"200":{"description":"The caller's preferences.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"theme":{"type":"string"},"themeName":{"type":"string"},"timezone":{"type":"string"},"webWalkthroughVersion":{"type":"integer","minimum":0,"maximum":9007199254740991},"soundEnabled":{"type":"boolean"},"locationSuggestionsEnabled":{"type":"boolean","description":"Whether the task location field calls the geocoding suggestion endpoint (proxied to Photon, an open-source third party). On by default."},"autoTaggingEnabled":{"type":"boolean","enum":[false],"description":"Deprecated compatibility field. AI-assisted tagging is unavailable, so responses always return false."},"taskView":{"type":"string","enum":["today","upcoming","all","completed"]},"taskSort":{"type":"string","enum":["default","due","priority","newest","title"]},"features":{"type":"object","properties":{"habits":{"type":"boolean"},"dashboard":{"type":"boolean"},"themes":{"type":"boolean"},"sharing":{"type":"boolean"},"notifications":{"type":"boolean"}},"required":["habits","dashboard","themes","sharing","notifications"],"additionalProperties":false},"notifications":{"type":"object","properties":{"inApp":{"type":"boolean"},"email":{"type":"boolean"},"push":{"type":"boolean"},"quietHoursStart":{"type":"integer","minimum":0,"maximum":23},"quietHoursEnd":{"type":"integer","minimum":0,"maximum":23},"dailyEmailCap":{"type":"integer","minimum":0,"maximum":100},"habitReminderHour":{"type":"integer","minimum":0,"maximum":23}},"required":["inApp","email","push","quietHoursStart","quietHoursEnd","dailyEmailCap","habitReminderHour"],"additionalProperties":false}},"required":["theme","themeName","timezone","webWalkthroughVersion","soundEnabled","locationSuggestionsEnabled","autoTaggingEnabled","taskView","taskSort","features","notifications"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"patch":{"summary":"Update the caller's preferences","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"theme":{"type":"string","enum":["light","dark","system"]},"themeName":{"type":"string","enum":["default","forest","dusk","mono"]},"timezone":{"type":"string"},"webWalkthroughVersion":{"type":"integer","minimum":0,"maximum":2},"soundEnabled":{"type":"boolean"},"locationSuggestionsEnabled":{"type":"boolean"},"autoTaggingEnabled":{"type":"boolean","description":"Deprecated compatibility field. Accepted, but AI-assisted tagging is unavailable and the stored/returned value remains false."},"taskView":{"type":"string","enum":["today","upcoming","all","completed"]},"taskSort":{"type":"string","enum":["default","due","priority","newest","title"]},"notifications":{"type":"object","properties":{"inApp":{"type":"boolean"},"email":{"type":"boolean"},"push":{"type":"boolean"},"quietHoursStart":{"type":"integer","minimum":0,"maximum":23},"quietHoursEnd":{"type":"integer","minimum":0,"maximum":23},"dailyEmailCap":{"type":"integer","minimum":0,"maximum":100},"habitReminderHour":{"type":"integer","minimum":0,"maximum":23}},"additionalProperties":false},"features":{"type":"object","properties":{"habits":{"type":"boolean"},"dashboard":{"type":"boolean"},"themes":{"type":"boolean"},"sharing":{"type":"boolean"},"notifications":{"type":"boolean"}},"additionalProperties":false}},"additionalProperties":false}}}},"responses":{"200":{"description":"The updated preferences.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"theme":{"type":"string"},"themeName":{"type":"string"},"timezone":{"type":"string"},"webWalkthroughVersion":{"type":"integer","minimum":0,"maximum":9007199254740991},"soundEnabled":{"type":"boolean"},"locationSuggestionsEnabled":{"type":"boolean","description":"Whether the task location field calls the geocoding suggestion endpoint (proxied to Photon, an open-source third party). On by default."},"autoTaggingEnabled":{"type":"boolean","enum":[false],"description":"Deprecated compatibility field. AI-assisted tagging is unavailable, so responses always return false."},"taskView":{"type":"string","enum":["today","upcoming","all","completed"]},"taskSort":{"type":"string","enum":["default","due","priority","newest","title"]},"features":{"type":"object","properties":{"habits":{"type":"boolean"},"dashboard":{"type":"boolean"},"themes":{"type":"boolean"},"sharing":{"type":"boolean"},"notifications":{"type":"boolean"}},"required":["habits","dashboard","themes","sharing","notifications"],"additionalProperties":false},"notifications":{"type":"object","properties":{"inApp":{"type":"boolean"},"email":{"type":"boolean"},"push":{"type":"boolean"},"quietHoursStart":{"type":"integer","minimum":0,"maximum":23},"quietHoursEnd":{"type":"integer","minimum":0,"maximum":23},"dailyEmailCap":{"type":"integer","minimum":0,"maximum":100},"habitReminderHour":{"type":"integer","minimum":0,"maximum":23}},"required":["inApp","email","push","quietHoursStart","quietHoursEnd","dailyEmailCap","habitReminderHour"],"additionalProperties":false}},"required":["theme","themeName","timezone","webWalkthroughVersion","soundEnabled","locationSuggestionsEnabled","autoTaggingEnabled","taskView","taskSort","features","notifications"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Validation failed.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/calendar":{"get":{"summary":"List dated tasks and goals in a window for the Calendar view","description":"Returns the top-level, non-deleted tasks with a due date and the non-archived goals with a target date that fall in `[from, to]`, resolved in the account's own timezone. Bounded to a 92-day window; not cursor-paginated. Per-entity cap of 500 (excess dropped, logged).","parameters":[{"name":"from","in":"query","required":true,"description":"Start of the window, inclusive (YYYY-MM-DD).","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}},{"name":"to","in":"query","required":true,"description":"End of the window, inclusive (YYYY-MM-DD).","schema":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$"}}],"responses":{"200":{"description":"Dated tasks and goals in the window.","content":{"application/json":{"schema":{"type":"object","properties":{"tasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"goals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"targetDate":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"archivedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"progress":{"type":"object","properties":{"completed":{"type":"number"},"total":{"type":"number"},"allComplete":{"type":"boolean"}},"required":["completed","total","allComplete"],"additionalProperties":false}},"required":["id","title","notes","targetDate","archivedAt","createdAt","updatedAt","progress"],"additionalProperties":false}}},"required":["tasks","goals"],"additionalProperties":false}}}},"400":{"description":"`from`/`to` missing, malformed, out of order, or wider than 92 days.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/calendar-feed":{"get":{"summary":"Get private calendar subscription status","responses":{"200":{"description":"Whether calendar sync is active.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"enabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["enabled"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Create or rotate the private calendar subscription URL","responses":{"201":{"description":"A one-time private URL for an iCalendar subscription. Rotating invalidates the previous URL.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"enabled":{"type":"boolean","enum":[true]},"url":{"type":"string","format":"uri"}},"required":["enabled","url"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Disable the private calendar subscription","responses":{"204":{"description":"Calendar subscription disabled."},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/geocode/suggest":{"get":{"summary":"Suggest places for a free-text location query","description":"Proxies the query to Photon, an open-source geocoder, and returns up to 5 plain-text place suggestions. Never a validation error for a short query — it answers `{ items: [] }` instead, the same way it answers `{ items: [] }` (rather than an error) for an account that has turned `locationSuggestionsEnabled` off. See docs/adr/0058-location-suggestions-via-photon.md.","parameters":[{"name":"q","in":"query","required":true,"description":"The location text typed so far.","schema":{"type":"string","maxLength":500}}],"responses":{"200":{"description":"Up to 5 place suggestions, possibly empty.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string"}},"required":["label"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces":{"get":{"summary":"List the caller's workspaces","description":"Every workspace this user is a member of — the personal one always first, then shared workspaces by name. For the switcher.","responses":{"200":{"description":"The caller's workspaces.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","shared"]},"role":{"type":"string","enum":["owner","member"]}},"required":["id","name","kind","role"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Create a shared workspace","description":"The caller becomes the owner and first member. A shared workspace has no journal — it is the container for working with someone, not for private reflection.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":100}},"required":["name"],"additionalProperties":false}}}},"responses":{"201":{"description":"The created workspace, with the caller as owner.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","shared"]},"role":{"type":"string","enum":["owner","member"]}},"required":["id","name","kind","role"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"The workspace needs a non-empty name.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces/members":{"get":{"summary":"List the members of the active workspace","description":"The peers the caller can assign a task to. The active workspace is the one the request resolves through membership, so the caller is by construction a member of the workspace whose peers they read. A personal workspace lists its owner alone, so the assignee picker always has at least \"me\".","responses":{"200":{"description":"The members of the active workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","enum":["owner","member"]}},"required":["userId","name","role"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces/{id}/members":{"get":{"summary":"List the members of a named workspace","description":"The members of a workspace the caller belongs to, named in the path rather than resolved from the active-workspace header. This is the read the management screens use, so opening one does not have to move the caller's active workspace. A workspace the caller is not a member of answers 404, the same as one that does not exist.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The members of the workspace.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","enum":["owner","member"]}},"required":["userId","name","role"],"additionalProperties":false}}},"required":["items"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such workspace, or the caller is not a member.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces/invitations":{"post":{"summary":"Invite someone to a shared workspace by email","description":"Mints a signed, expiring token (7 days) and emails the link. Only the workspace owner can invite; the workspace must be shared, because a personal workspace can never receive a member. The accept URL is returned to the owner too, so an invite can be shared directly when email is not configured.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string","minLength":1},"email":{"type":"string","format":"email","pattern":"^(?!\\.)(?!.*\\.\\.)([A-Za-z0-9_'+\\-\\.]*)[A-Za-z0-9_+-]@([A-Za-z0-9][A-Za-z0-9\\-]*\\.)+[A-Za-z]{2,}$"}},"required":["workspaceId","email"],"additionalProperties":false}}}},"responses":{"201":{"description":"The invitation was created and emailed.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"url":{"type":"string"},"email":{"type":"string"}},"required":["url","email"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The caller is not the workspace's owner.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such workspace, or the caller is not a member.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"The email is invalid, or the workspace is personal and cannot receive members.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces/invitations/accept":{"post":{"summary":"Accept an invitation","description":"Redeems an invitation token. The email link lands on the /invitations/accept confirm page, which calls this same-origin POST — accepting mutates membership, so there is no GET (prefetchers and cross-site tags would fire it without the user's intent). The signed-in user's email must match the address the invitation was sent to, so a leaked link is not a way in for whoever holds it. Requires a signed-in session — an API key cannot accept (it carries no email).","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":1,"maxLength":2048}},"required":["token"],"additionalProperties":false}}}},"responses":{"200":{"description":"The workspace the caller is now a member of.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"workspaceId":{"type":"string"},"workspaceName":{"type":"string"}},"required":["workspaceId","workspaceName"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The signed-in email does not match the invitation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"The token is invalid, expired, or the workspace is no longer shared.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces/{id}":{"patch":{"summary":"Rename a workspace","description":"Owner-only. The name must be 1–100 characters after trimming. A personal workspace can be renamed too — only `kind` is immutable (ADR 0046). Requires a signed-in session — an API key cannot rename a workspace on its holder's behalf.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100}},"required":["name"],"additionalProperties":false}}}},"responses":{"200":{"description":"The renamed workspace, with the caller's role.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","shared"]},"role":{"type":"string","enum":["owner","member"]}},"required":["id","name","kind","role"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The caller is not the workspace's owner, or presented an API key instead of a session — the management routes are signed-in only.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such workspace, or the caller is not a member.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Delete a workspace","description":"Owner-only, interactive-session-only. A soft delete marks the row and sweeps it after the retention window (ADR 0045); members fall back to their personal workspace, and the workspace's tasks are hard-deleted with the row. A personal workspace cannot be deleted. The last owner of a shared workspace can delete it — there is no co-owner requirement.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"The workspace was soft-deleted."},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The caller is not the workspace's owner, or presented an API key instead of a session — the management routes are signed-in only.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such workspace, or the caller is not a member.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"A personal workspace cannot be mutated in this way.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces/{id}/members/{userId}":{"delete":{"summary":"Remove a member from a shared workspace","description":"Owner-only, interactive-session-only. The target `userId` is the member to remove; the owner cannot remove themselves (leave instead) and the last owner cannot be removed. A personal workspace has no members to remove.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"userId","in":"path","required":true,"description":"The member's user id.","schema":{"type":"string"}}],"responses":{"204":{"description":"The member was removed."},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The caller is not the workspace's owner, or presented an API key instead of a session — the management routes are signed-in only.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such workspace, or the caller is not a member.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The last owner cannot leave or be removed (transfer ownership first), and a transfer to someone who is already the owner is a no-op the API refuses.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"A personal workspace cannot be mutated in this way.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces/{id}/transfer":{"post":{"summary":"Transfer ownership to another member","description":"Owner-only, interactive-session-only. Swaps the owner role with the named member; the caller becomes a member. There is no co-owner state — a workspace has exactly one owner at a time (ADR 0046). The target must already be a member. The response returns the workspace with the caller's new role (`member`).","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"toUserId":{"type":"string","minLength":1}},"required":["toUserId"],"additionalProperties":false}}}},"responses":{"200":{"description":"The workspace, with the caller's new role.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","shared"]},"role":{"type":"string","enum":["owner","member"]}},"required":["id","name","kind","role"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"The caller is not the workspace's owner, or presented an API key instead of a session — the management routes are signed-in only.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such workspace, the caller is not a member, or the named target is not a member — the three are indistinguishable on purpose.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The last owner cannot leave or be removed (transfer ownership first), and a transfer to someone who is already the owner is a no-op the API refuses.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"A personal workspace cannot be mutated in this way.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/workspaces/{id}/leave":{"post":{"summary":"Leave a shared workspace","description":"Interactive-session-only. The caller removes their own membership. The last owner cannot leave (the workspace would be orphaned); transfer ownership first. A personal workspace cannot be left.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"The caller left the workspace."},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Presented an API key instead of a session — the management routes are signed-in only.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such workspace, or the caller is not a member.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"409":{"description":"The last owner cannot leave or be removed (transfer ownership first), and a transfer to someone who is already the owner is a no-op the API refuses.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"A personal workspace cannot be mutated in this way.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/shared":{"get":{"summary":"List records shared with the caller","description":"Active grants where the caller is the recipient — not revoked and not past expiry (the boundary is exclusive). Cursor-paginated by (createdAt, id). This is the one path that is not filtered on the caller's active workspace: it is filtered on the grant's workspace instead, which is where the shared record lives.","parameters":[{"in":"query","name":"limit","required":false,"description":"Page size, default 50, max 200.","schema":{"type":"integer","minimum":1,"maximum":200}},{"in":"query","name":"cursor","required":false,"description":"Opaque cursor from a previous page's nextCursor.","schema":{"type":"string"}}],"responses":{"200":{"description":"Grants shared with the caller, oldest first.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"resourceType":{"type":"string","enum":["task","journal_entry","habit"]},"resourceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"grantedBy":{"type":"object","properties":{"userId":{"type":"string"},"name":{"type":"string"}},"required":["userId","name"],"additionalProperties":false},"canComment":{"type":"boolean"},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"resourceTitle":{"nullable":true,"type":"string"}},"required":["id","resourceType","resourceId","grantedBy","canComment","expiresAt","createdAt","resourceTitle"],"additionalProperties":false}},"nextCursor":{"nullable":true,"type":"string"}},"required":["items","nextCursor"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"post":{"summary":"Share a record with an email address","description":"Creates a grant. The record must exist in the caller's active workspace. The recipient is named by email without revealing whether that address already has a TodoZen account: both cases create the same grant and return the same 201 response. A grant for a future account waits until that address signs in. Re-sharing the same record to the same address updates canComment and expiry in place and un-revokes the existing grant.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resourceType":{"type":"string","enum":["task","journal_entry","habit"]},"resourceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"email":{"type":"string","minLength":3,"maxLength":320},"canComment":{"type":"boolean"},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},"required":["resourceType","resourceId","email"],"additionalProperties":false}}}},"responses":{"201":{"description":"The created or updated grant.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"resourceType":{"type":"string","enum":["task","journal_entry","habit"]},"resourceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"grantedBy":{"type":"object","properties":{"userId":{"type":"string"},"name":{"type":"string"}},"required":["userId","name"],"additionalProperties":false},"canComment":{"type":"boolean"},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"resourceTitle":{"nullable":true,"type":"string"}},"required":["id","resourceType","resourceId","grantedBy","canComment","expiresAt","createdAt","resourceTitle"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"400":{"description":"Body failed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"The record does not exist, is deleted, or is outside the caller's active workspace. Recipient existence is never reported.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"422":{"description":"The resourceType is not in the closed set, or the grant names the creator as its recipient.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}},"/api/v1/shared/{id}":{"get":{"summary":"Resolve a grant to its record","description":"The dedicated read path. Resolves the grant first (the caller must be its recipient, and the grant must be active), then loads the record by id from the grant's own workspace — not the caller's. A task or journal entry resolves to its full DTO; a habit resolves to its definition only, because a streak is personal to a member and a grantee is not one.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The grant and the resolved record.","content":{"application/json":{"schema":{"type":"object","properties":{"grant":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"resourceType":{"type":"string","enum":["task","journal_entry","habit"]},"resourceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"grantedBy":{"type":"object","properties":{"userId":{"type":"string"},"name":{"type":"string"}},"required":["userId","name"],"additionalProperties":false},"canComment":{"type":"boolean"},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"resourceTitle":{"nullable":true,"type":"string"}},"required":["id","resourceType","resourceId","grantedBy","canComment","expiresAt","createdAt","resourceTitle"],"additionalProperties":false},"item":{"anyOf":[{"type":"object","properties":{"kind":{"type":"string","enum":["task"]},"item":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"notes":{"nullable":true,"type":"string"},"priority":{"nullable":true,"type":"string","enum":["high","medium","low"]},"dueAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"completedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"tags":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"parentId":{"nullable":true,"type":"string"},"goalId":{"nullable":true,"type":"string"},"recurrence":{"nullable":true,"type":"string"},"location":{"nullable":true,"type":"string"},"assigneeId":{"nullable":true,"type":"string"}},"required":["id","title","notes","priority","dueAt","completedAt","tags","createdAt","updatedAt","parentId","goalId","recurrence","location","assigneeId"],"additionalProperties":false}},"required":["kind","item"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","enum":["journal_entry"]},"item":{"type":"object","properties":{"id":{"type":"string"},"date":{"type":"string"},"body":{"type":"string"},"mood":{"nullable":true,"type":"string","enum":["rough","low","okay","good","great"]},"tags":{"type":"array","items":{"type":"string"}},"pinnedAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","date","body","mood","tags","pinnedAt","createdAt","updatedAt"],"additionalProperties":false}},"required":["kind","item"],"additionalProperties":false},{"type":"object","properties":{"kind":{"type":"string","enum":["habit"]},"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"notes":{"nullable":true,"type":"string"},"schedule":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z))$"}},"required":["id","name","notes","schedule","createdAt","updatedAt"],"additionalProperties":false}},"required":["kind","item"],"additionalProperties":false}]}},"required":["grant","item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"The grant does not exist, is revoked, has expired, or is not yours to read; or the underlying record was deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}},"delete":{"summary":"Revoke a grant","description":"Sets revokedAt. Either the creator or the recipient may revoke — the creator stops sharing, the recipient stops receiving. The row is kept, not deleted, so revocation is auditable and a re-share un-revokes in place.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"The revoked grant.","content":{"application/json":{"schema":{"type":"object","properties":{"item":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"resourceType":{"type":"string","enum":["task","journal_entry","habit"]},"resourceId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-8][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}|00000000-0000-0000-0000-000000000000|ffffffff-ffff-ffff-ffff-ffffffffffff)$"},"grantedBy":{"type":"object","properties":{"userId":{"type":"string"},"name":{"type":"string"}},"required":["userId","name"],"additionalProperties":false},"canComment":{"type":"boolean"},"expiresAt":{"nullable":true,"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d:[0-5]\\d(?:\\.\\d+)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"},"resourceTitle":{"nullable":true,"type":"string"}},"required":["id","resourceType","resourceId","grantedBy","canComment","expiresAt","createdAt","resourceTitle"],"additionalProperties":false}},"required":["item"],"additionalProperties":false}}}},"401":{"description":"No valid session.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"403":{"description":"Cross-origin request without an API key (docs/adr/0021-bearer-keys-may-cross-origins.md), or an API key lacking the scope this route needs.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"404":{"description":"No such grant, or not yours to revoke.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}},"429":{"description":"Rate limited.","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"requestId":{"type":"string"},"details":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"],"additionalProperties":false}}},"required":["code","message","requestId"],"additionalProperties":false}},"required":["error"],"additionalProperties":false}}}}}}}}}