{"openapi":"3.1.0","info":{"title":"GUNGUN128 API","version":"1.0.0","description":"Self-hosted task management API. Browser clients use HttpOnly session cookies and same-origin checks for mutations; programmatic clients use revocable bearer tokens. Workspace IDs and resource IDs never grant access by themselves."},"servers":[{"url":"/api/v1"}],"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"Raw API token returned once by POST /auth/tokens."},"session":{"type":"apiKey","in":"cookie","name":"hopya_session","description":"HttpOnly browser session; unsafe requests also require a matching Origin."}},"schemas":{"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"],"additionalProperties":false},"Success":{"type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false},"User":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"email":{"type":"string","format":"email"},"isAdmin":{"type":"boolean"}},"required":["id","name","email","isAdmin"]},"AdminUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string","format":"email"},"isAdmin":{"type":"boolean"},"disabled":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","email","isAdmin","disabled","createdAt"]},"Workspace":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","createdAt"]},"ChecklistEntry":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"text":{"type":"string","maxLength":200},"done":{"type":"boolean"}},"required":["id","text","done"]},"Item":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"nodeId":{"type":"string","format":"uuid"},"title":{"type":"string","maxLength":300},"description":{"type":"string","maxLength":50000},"status":{"type":"string","minLength":1,"maxLength":64},"boardRank":{"type":"number"},"priority":{"type":"string","enum":["none","low","medium","high","urgent"]},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"dueDate":{"anyOf":[{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string","maxLength":60},"maxItems":30},"customFields":{"type":"object","properties":{},"additionalProperties":true},"assigneeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"checklist":{"type":"array","items":{"$ref":"#/components/schemas/ChecklistEntry"},"maxItems":100},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"bodyRevision":{"type":"integer","minimum":1},"archivedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","workspaceId","nodeId","title","description","status","boardRank","priority","startDate","dueDate","tags","customFields","assigneeId","checklist","parentId","bodyRevision","archivedAt","createdAt","updatedAt"]},"ItemCreate":{"type":"object","properties":{"nodeId":{"type":"string","format":"uuid"},"title":{"type":"string","minLength":1,"maxLength":300},"description":{"type":"string","maxLength":50000,"default":""},"status":{"type":"string","minLength":1,"maxLength":64},"boardRank":{"type":"number"},"priority":{"type":"string","enum":["none","low","medium","high","urgent"]},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"dueDate":{"anyOf":[{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"maxItems":30},"customFields":{"type":"object","properties":{},"maxProperties":100,"additionalProperties":{"anyOf":[{"type":"string","maxLength":10000},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":100},{"type":"null"}]}},"assigneeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"checklist":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","maxLength":100},"text":{"type":"string","maxLength":400},"done":{"type":"boolean"}},"required":["text"],"additionalProperties":false},"maxItems":100},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]}},"required":["nodeId","title"],"additionalProperties":false},"ItemPatch":{"type":"object","properties":{"nodeId":{"type":"string","format":"uuid"},"title":{"type":"string","minLength":1,"maxLength":300},"description":{"type":"string","maxLength":50000,"default":""},"status":{"type":"string","minLength":1,"maxLength":64},"boardRank":{"type":"number"},"priority":{"type":"string","enum":["none","low","medium","high","urgent"]},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"dueDate":{"anyOf":[{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"maxItems":30},"customFields":{"type":"object","properties":{},"maxProperties":100,"additionalProperties":{"anyOf":[{"type":"string","maxLength":10000},{"type":"number"},{"type":"boolean"},{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":100},{"type":"null"}]}},"assigneeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"checklist":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","maxLength":100},"text":{"type":"string","maxLength":400},"done":{"type":"boolean"}},"required":["text"],"additionalProperties":false},"maxItems":100},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"expectedUpdatedAt":{"type":"string","format":"date-time"}},"additionalProperties":false},"Node":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":50000},"kind":{"type":"string","enum":["project","folder","list"]},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string","enum":["diamond","briefcase","target","home","star","heart","globe","clock","mapPin","settings","lock","users","user","folder","archive","bookmark","list","checklist","calendar","flag","package","shoppingBag","fileText","inbox","trash","pencil","eye","eyeOff","sparkles","code","link","comment","save"]},{"type":"null"}]},"color":{"anyOf":[{"type":"string","pattern":"^#[0-9a-f]{6}$","example":"#c45d0a","description":"Normalized lowercase six-digit hex color."},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time"}},"required":["id","workspaceId","name","description","kind","parentId","icon","color","createdAt"]},"NodeCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":50000},"kind":{"type":"string","enum":["project","folder","list"]},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string","enum":["diamond","briefcase","target","home","star","heart","globe","clock","mapPin","settings","lock","users","user","folder","archive","bookmark","list","checklist","calendar","flag","package","shoppingBag","fileText","inbox","trash","pencil","eye","eyeOff","sparkles","code","link","comment","save"]},{"type":"null"}]},"color":{"anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"string","enum":["slate","orange","amber","green","teal","blue","violet","rose"]},{"type":"null"}],"description":"Six-digit hex color. Legacy catalog names remain accepted and are returned as their normalized hex value."}},"required":["name","kind"],"additionalProperties":false},"NodePatch":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":50000},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"expectedParentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"icon":{"anyOf":[{"type":"string","enum":["diamond","briefcase","target","home","star","heart","globe","clock","mapPin","settings","lock","users","user","folder","archive","bookmark","list","checklist","calendar","flag","package","shoppingBag","fileText","inbox","trash","pencil","eye","eyeOff","sparkles","code","link","comment","save"]},{"type":"null"}]},"color":{"anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"string","enum":["slate","orange","amber","green","teal","blue","violet","rose"]},{"type":"null"}],"description":"Six-digit hex color. Legacy catalog names remain accepted and are returned as their normalized hex value."}},"additionalProperties":false,"anyOf":[{"required":["name"]},{"required":["description"]},{"required":["parentId"]},{"required":["icon"]},{"required":["color"]}],"dependentRequired":{"expectedParentId":["parentId"]}},"FieldSettings":{"type":"object","properties":{"dateFormat":{"type":"string","enum":["yyyy-MM-dd","MMM d, yyyy","MMMM d, yyyy","dd/MM/yyyy"]},"maxRating":{"type":"integer","minimum":1,"maximum":10},"formula":{"type":"string","minLength":1,"maxLength":200}},"additionalProperties":false},"Field":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"type":{"type":"string","enum":["text","number","date","datetime","checkbox","select","checklist","rating","formula"]},"options":{"type":"array","items":{"type":"string","maxLength":120},"maxItems":100},"settings":{"$ref":"#/components/schemas/FieldSettings"}},"required":["id","workspaceId","name","type","options"]},"FieldCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"type":{"type":"string","enum":["text","number","date","datetime","checkbox","select","checklist","rating","formula"]},"options":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":100},"settings":{"$ref":"#/components/schemas/FieldSettings"},"projectId":{"type":"string","format":"uuid"}},"required":["name","type"],"additionalProperties":false},"FieldPatch":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"options":{"type":"array","items":{"type":"string","minLength":1,"maxLength":120},"maxItems":100},"settings":{"$ref":"#/components/schemas/FieldSettings"}},"additionalProperties":false,"minProperties":1},"Status":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9_-]*$"},"name":{"type":"string","minLength":1,"maxLength":120},"color":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#2f7d32"},"completed":{"type":"boolean"}},"required":["id","name","color","completed"],"additionalProperties":false},"ProjectFields":{"type":"object","properties":{"projectId":{"type":"string","format":"uuid"},"fieldIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":100,"uniqueItems":true},"builtInFields":{"type":"array","items":{"type":"string","enum":["priority","startDate","tags","description","nodeId","createdAt","updatedAt"]},"maxItems":7,"uniqueItems":true},"statuses":{"type":"array","items":{"$ref":"#/components/schemas/Status"},"minItems":1,"maxItems":50},"dateFormat":{"type":"string","enum":["yyyy-MM-dd","MMM d, yyyy","MMMM d, yyyy","dd/MM/yyyy"]},"updatedAt":{"type":"string","format":"date-time"}},"required":["projectId","fieldIds","builtInFields","statuses","updatedAt"]},"ListStatuses":{"type":"object","properties":{"listId":{"type":"string","format":"uuid"},"statuses":{"type":"array","items":{"$ref":"#/components/schemas/Status"},"minItems":1,"maxItems":50},"updatedAt":{"type":"string","format":"date-time"},"inheritedProjectUpdatedAt":{"type":"string","format":"date-time"}},"required":["listId","updatedAt"]},"ListTagColors":{"type":"object","properties":{"listId":{"type":"string","format":"uuid"},"colors":{"type":"object","properties":{},"maxProperties":30,"additionalProperties":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#2f7d32"}},"updatedAt":{"type":"string","format":"date-time"}},"required":["listId","colors","updatedAt"]},"ListViewSettings":{"type":"object","properties":{"view":{"type":"string","const":"list"},"projectId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"columnOrder":{"type":"array","items":{"type":"string","maxLength":43},"maxItems":111,"uniqueItems":true},"hiddenColumns":{"type":"array","items":{"type":"string","maxLength":43},"maxItems":110,"uniqueItems":true},"sort":{"anyOf":[{"type":"object","properties":{"column":{"type":"string","maxLength":43},"direction":{"type":"string","enum":["asc","desc"]}},"required":["column","direction"],"additionalProperties":false},{"type":"null"}]},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["view","projectId","columnOrder","hiddenColumns","sort","updatedAt"]},"Role":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"permissions":{"type":"array","items":{"type":"string","enum":["items:read","items:write","items:delete","documents:read","documents:write","documents:delete","comments:create","comments:manage","structure:write","members:manage","roles:manage","workspace:manage","automations:manage","credentials:manage","agent:use"]},"uniqueItems":true},"isOwner":{"type":"boolean"}},"required":["id","workspaceId","name","permissions","isOwner"]},"Membership":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"roleId":{"type":"string","format":"uuid"}},"required":["userId","workspaceId","roleId"]},"Attachment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":255},"size":{"type":"integer","minimum":0},"contentType":{"type":"string","maxLength":127},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","size","contentType","createdAt"]},"CommentReaction":{"type":"object","properties":{"emoji":{"type":"string","enum":["👍","❤️","😂","🎉","😕","👀"]},"count":{"type":"integer","minimum":1},"reactedByMe":{"type":"boolean"}},"required":["emoji","count","reactedByMe"]},"CommentAnchor":{"type":"object","properties":{"revision":{"type":"integer","minimum":1},"start":{"type":"integer","minimum":0},"end":{"type":"integer","minimum":1},"exact":{"type":"string","minLength":1,"maxLength":2000},"prefix":{"type":"string","maxLength":200},"suffix":{"type":"string","maxLength":200},"state":{"type":"string","enum":["attached","orphaned"]}},"required":["revision","start","end","exact","prefix","suffix","state"],"additionalProperties":false},"CommentAnchorInput":{"type":"object","properties":{"revision":{"type":"integer","minimum":1},"start":{"type":"integer","minimum":0},"end":{"type":"integer","minimum":1},"exact":{"type":"string","minLength":1,"maxLength":2000},"prefix":{"type":"string","maxLength":200},"suffix":{"type":"string","maxLength":200}},"required":["revision","start","end","exact"],"additionalProperties":false},"Comment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"itemId":{"type":"string","format":"uuid"},"documentId":{"type":"string","format":"uuid"},"authorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"authorName":{"type":"string","maxLength":120},"body":{"type":"string","maxLength":10000},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"anchor":{"anyOf":[{"$ref":"#/components/schemas/CommentAnchor"},{"type":"null"}]},"reactions":{"type":"array","items":{"$ref":"#/components/schemas/CommentReaction"},"maxItems":6},"createdAt":{"type":"string","format":"date-time"},"deletedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","workspaceId","authorId","authorName","body","parentId","anchor","reactions","createdAt","deletedAt"]},"Document":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"title":{"type":"string","minLength":1,"maxLength":300},"body":{"type":"string","maxLength":50000},"bodyRevision":{"type":"integer","minimum":1},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"createdByName":{"anyOf":[{"type":"string"},{"type":"null"}]},"updatedByName":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","workspaceId","parentId","title","body","bodyRevision","createdAt","updatedAt","createdByName","updatedByName"]},"Notification":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["assignment","mention"]},"itemId":{"type":"string","format":"uuid"},"itemTitle":{"type":"string","maxLength":300},"commentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"actorId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"actorName":{"type":"string","maxLength":120},"createdAt":{"type":"string","format":"date-time"},"readAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","workspaceId","type","itemId","itemTitle","commentId","actorId","actorName","createdAt","readAt"]},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"url":{"type":"string","format":"uri","maxLength":2000},"events":{"type":"array","items":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"minItems":1,"maxItems":7},"enabled":{"type":"boolean"},"signingVersion":{"type":"integer","enum":[1,2],"description":"1 retains the legacy SHA-256(secret + \".\" + body) digest until rotation; 2 uses HMAC-SHA256 over the exact body. Both versions reject all 3xx responses. Redirect-dependent integrations must use the final endpoint URL: this intentional security-hardening compatibility break prevents forwarding payloads or secrets beyond the checked destination."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","url","events","enabled","signingVersion","createdAt","updatedAt"]},"Action":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","const":"webhook"},"config":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000},"method":{"type":"string","enum":["POST","PUT","PATCH"],"default":"POST"}},"required":["url"],"additionalProperties":false}},"required":["type","config"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"email"},"config":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string","format":"email","maxLength":254},"minItems":1,"maxItems":10},"subject":{"type":"string","minLength":1,"maxLength":200}},"required":["to","subject"],"additionalProperties":false}},"required":["type","config"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"http"},"config":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"default":"POST"},"headers":{"type":"object","properties":{},"maxProperties":20,"additionalProperties":{"type":"string","maxLength":2000}},"body":{"type":"string","maxLength":20000}},"required":["url"],"additionalProperties":false}},"required":["type","config"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","const":"log"},"config":{"type":"object","properties":{"message":{"type":"string","maxLength":2000}},"required":["message"],"additionalProperties":false}},"required":["type","config"],"additionalProperties":false}],"examples":[{"type":"log","config":{"message":"Task event received"}},{"type":"http","config":{"url":"https://hooks.example.test/tasks","method":"POST","headers":{"x-source":"hopya"},"body":"{{event}}"}}]},"Automation":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"event":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"version":{"type":"integer","minimum":1},"enabled":{"type":"boolean"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"maxItems":20},"action":{"$ref":"#/components/schemas/Action"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","workspaceId","name","event","version","enabled","steps","createdAt","updatedAt"],"title":"Legacy linear automation"},{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"event":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"version":{"type":"integer","minimum":1},"enabled":{"type":"boolean"},"graph":{"type":"boolean","const":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","workspaceId","name","event","version","enabled","graph","createdAt","updatedAt"],"additionalProperties":false,"title":"Published graph automation"}],"description":"Current automation metadata. Linear versions include steps and retain the single-action compatibility alias; graph versions expose graph=true and are read through draft/version routes. Both linear and graph outbound requests reject all 3xx responses; legacy redirect behavior is intentionally not retained. Use final endpoint URLs."},"AutomationInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"event":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"action":{"$ref":"#/components/schemas/Action"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"maxItems":20},"enabled":{"type":"boolean","default":true}},"required":["name","event"],"additionalProperties":false,"oneOf":[{"required":["action"],"not":{"required":["steps"]}},{"required":["steps"],"not":{"required":["action"]}}]},"AutomationPatch":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"event":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"action":{"$ref":"#/components/schemas/Action"},"steps":{"type":"array","items":{"$ref":"#/components/schemas/Action"},"minItems":1,"maxItems":20},"enabled":{"type":"boolean"}},"additionalProperties":false,"not":{"required":["action","steps"]}},"GraphNode":{"oneOf":[{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","const":"trigger"},"position":{"type":"object","properties":{"x":{"type":"number","minimum":-100000,"maximum":100000},"y":{"type":"number","minimum":-100000,"maximum":100000}},"required":["x","y"],"additionalProperties":false},"config":{"type":"object","properties":{"event":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]}},"required":["event"],"additionalProperties":false}},"required":["id","type","position","config"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","const":"http"},"position":{"type":"object","properties":{"x":{"type":"number","minimum":-100000,"maximum":100000},"y":{"type":"number","minimum":-100000,"maximum":100000}},"required":["x","y"],"additionalProperties":false},"config":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"default":"POST"},"headers":{"type":"object","properties":{},"maxProperties":20,"propertyNames":{"type":"string","maxLength":100},"additionalProperties":{"type":"string","maxLength":2000},"description":"Public request headers only. Sensitive authentication and hop-by-hop names are rejected; use credentialId for authentication."},"body":{"type":"string","maxLength":20000},"credentialId":{"type":"string","format":"uuid"},"legacyHeaderMigrationRequired":{"type":"boolean","const":true,"description":"Legacy inline header values were removed; attach a credential and delete this marker before publishing."}},"required":["url"],"additionalProperties":false}},"required":["id","type","position","config"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","const":"webhook"},"position":{"type":"object","properties":{"x":{"type":"number","minimum":-100000,"maximum":100000},"y":{"type":"number","minimum":-100000,"maximum":100000}},"required":["x","y"],"additionalProperties":false},"config":{"type":"object","properties":{"url":{"type":"string","format":"uri","maxLength":2000},"method":{"type":"string","enum":["POST","PUT","PATCH"],"default":"POST"},"headers":{"type":"object","properties":{},"maxProperties":20,"propertyNames":{"type":"string","maxLength":100},"additionalProperties":{"type":"string","maxLength":2000},"description":"Public request headers only. Sensitive authentication and hop-by-hop names are rejected; use credentialId for authentication."},"body":{"type":"string","maxLength":20000},"credentialId":{"type":"string","format":"uuid"},"legacyHeaderMigrationRequired":{"type":"boolean","const":true,"description":"Legacy inline header values were removed; attach a credential and delete this marker before publishing."}},"required":["url"],"additionalProperties":false}},"required":["id","type","position","config"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","const":"email"},"position":{"type":"object","properties":{"x":{"type":"number","minimum":-100000,"maximum":100000},"y":{"type":"number","minimum":-100000,"maximum":100000}},"required":["x","y"],"additionalProperties":false},"config":{"type":"object","properties":{"to":{"type":"array","items":{"type":"string","format":"email","maxLength":254},"minItems":1,"maxItems":10},"subject":{"type":"string","minLength":1,"maxLength":200}},"required":["to","subject"],"additionalProperties":false}},"required":["id","type","position","config"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","const":"log"},"position":{"type":"object","properties":{"x":{"type":"number","minimum":-100000,"maximum":100000},"y":{"type":"number","minimum":-100000,"maximum":100000}},"required":["x","y"],"additionalProperties":false},"config":{"type":"object","properties":{"message":{"type":"string","maxLength":2000}},"required":["message"],"additionalProperties":false}},"required":["id","type","position","config"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","const":"update_item"},"position":{"type":"object","properties":{"x":{"type":"number","minimum":-100000,"maximum":100000},"y":{"type":"number","minimum":-100000,"maximum":100000}},"required":["x","y"],"additionalProperties":false},"config":{"type":"object","properties":{"patch":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300},"description":{"type":"string","maxLength":50000},"status":{"type":"string","minLength":1,"maxLength":64},"priority":{"type":"string","enum":["none","low","medium","high","urgent"]},"startDate":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}]},"dueDate":{"anyOf":[{"type":"string","maxLength":64},{"type":"null"}]},"assigneeId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"tags":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"maxItems":30}},"additionalProperties":false,"minProperties":1}},"required":["patch"],"additionalProperties":false}},"required":["id","type","position","config"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","const":"condition"},"position":{"type":"object","properties":{"x":{"type":"number","minimum":-100000,"maximum":100000},"y":{"type":"number","minimum":-100000,"maximum":100000}},"required":["x","y"],"additionalProperties":false},"config":{"type":"object","properties":{"path":{"type":"string","minLength":1,"maxLength":200},"operator":{"type":"string","enum":["equals","not_equals","exists","contains"]},"value":{}},"required":["path","operator"],"additionalProperties":false}},"required":["id","type","position","config"],"additionalProperties":false},{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","const":"switch"},"position":{"type":"object","properties":{"x":{"type":"number","minimum":-100000,"maximum":100000},"y":{"type":"number","minimum":-100000,"maximum":100000}},"required":["x","y"],"additionalProperties":false},"config":{"type":"object","properties":{"path":{"type":"string","minLength":1,"maxLength":200},"cases":{"type":"array","items":{"type":"object","properties":{"branch":{"type":"string","minLength":1,"maxLength":100},"value":{"type":["string","number","boolean","null"]}},"required":["branch","value"],"additionalProperties":false},"minItems":1,"maxItems":20},"defaultBranch":{"type":"string","minLength":1,"maxLength":100}},"required":["path","cases","defaultBranch"],"additionalProperties":false}},"required":["id","type","position","config"],"additionalProperties":false}]},"GraphEdge":{"type":"object","properties":{"id":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"source":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"target":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"branch":{"type":"string","minLength":1,"maxLength":100}},"required":["id","source","target"],"additionalProperties":false},"AutomationGraph":{"type":"object","properties":{"nodes":{"type":"array","items":{"$ref":"#/components/schemas/GraphNode"},"maxItems":50},"edges":{"type":"array","items":{"$ref":"#/components/schemas/GraphEdge"},"maxItems":75}},"required":["nodes","edges"],"additionalProperties":false,"description":"A bounded directed acyclic graph with exactly one trigger. Control-flow branches are exclusive; parallel fan-out, loops, unreachable nodes, and unsafe or non-upstream output references are rejected. Execution rechecks the recorded publisher's current workspace membership and items:read before execution and before every node. update_item additionally rechecks items:read and items:write immediately before mutating only the triggering task."},"GraphValidation":{"type":"object","properties":{"valid":{"type":"boolean"},"errors":{"type":"array","items":{"type":"string"}}},"required":["valid","errors"],"additionalProperties":false},"AutomationDraft":{"type":"object","properties":{"revision":{"type":"integer","minimum":0},"graph":{"$ref":"#/components/schemas/AutomationGraph"},"updatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["revision","graph","updatedAt"],"additionalProperties":false},"AutomationDraftSaved":{"type":"object","properties":{"revision":{"type":"integer","minimum":1},"graph":{"$ref":"#/components/schemas/AutomationGraph"},"updatedAt":{"type":"string","format":"date-time"},"validation":{"$ref":"#/components/schemas/GraphValidation"}},"required":["revision","graph","updatedAt","validation"],"additionalProperties":false},"AutomationVersionSummary":{"type":"object","properties":{"version":{"type":"integer","minimum":1},"format":{"type":"string","enum":["linear","graph"]},"publisherId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"publishedAt":{"type":"string","format":"date-time"}},"required":["version","format","publisherId","publishedAt"],"additionalProperties":false},"AutomationVersion":{"type":"object","properties":{"version":{"type":"integer","minimum":1},"format":{"type":"string","enum":["linear","graph"]},"graph":{"$ref":"#/components/schemas/AutomationGraph"},"publisherId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"publishedAt":{"type":"string","format":"date-time"}},"required":["version","format","graph","publisherId","publishedAt"],"additionalProperties":false},"AutomationCatalog":{"type":"object","properties":{"limits":{"type":"object","properties":{"maxNodes":{"type":"integer","const":50},"maxEdges":{"type":"integer","const":75},"maxGraphBytes":{"type":"integer","const":262144},"maxNodeConfigBytes":{"type":"integer","const":32768},"maxExecutionNodes":{"type":"integer","const":50}},"required":["maxNodes","maxEdges","maxGraphBytes","maxNodeConfigBytes","maxExecutionNodes"],"additionalProperties":false},"events":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"output":{"type":"object","properties":{},"additionalProperties":true}},"required":["type","output"],"additionalProperties":false}},"nodes":{"type":"array","items":{"type":"object","properties":{"type":{"type":"string","enum":["trigger","http","webhook","email","log","update_item","condition","switch"]},"kind":{"type":"string","enum":["trigger","action","control"]},"inputs":{"type":"object","properties":{},"additionalProperties":true},"outputs":{"type":"object","properties":{},"additionalProperties":true},"config":{"type":"object","properties":{},"additionalProperties":true}},"required":["type","kind","inputs","outputs","config"],"additionalProperties":false}}},"required":["limits","events","nodes"],"additionalProperties":false},"GraphPreview":{"type":"object","properties":{"valid":{"type":"boolean"},"errors":{"type":"array","items":{"type":"string"}},"uncertain":{"type":"boolean"},"path":{"type":"array","items":{"type":"object","properties":{"nodeId":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","enum":["trigger","http","webhook","email","log","update_item","condition","switch"]},"branch":{"type":"string","minLength":1,"maxLength":100},"effect":{"type":"string","const":"none"},"output":{},"uncertain":{"type":"boolean"},"candidateBranches":{"type":"array","items":{"type":"string","minLength":1,"maxLength":100}}},"required":["nodeId","type","effect"],"additionalProperties":false},"maxItems":50}},"required":["valid","errors","path"],"additionalProperties":false},"AutomationCredential":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string","maxLength":120},"type":{"type":"string","enum":["bearer","api_key","basic","custom_headers","oauth2"]},"origin":{"type":"string","format":"uri","maxLength":2000},"pathPrefix":{"anyOf":[{"type":"string","maxLength":1000},{"type":"null"}]},"version":{"type":"integer","minimum":1},"status":{"type":"string","enum":["active","revoked"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","name","type","origin","pathPrefix","version","status","createdAt","updatedAt"],"additionalProperties":false,"description":"Write-only credential material is never returned."},"AutomationCredentialCreate":{"oneOf":[{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"type":{"type":"string","const":"bearer"},"origin":{"type":"string","format":"uri","maxLength":2000},"pathPrefix":{"anyOf":[{"type":"string","maxLength":1000,"default":null},{"type":"null"}]},"secret":{"type":"object","properties":{"token":{"type":"string","minLength":1,"maxLength":8192,"writeOnly":true}},"required":["token"],"additionalProperties":false,"title":"Bearer secret","writeOnly":true}},"required":["name","type","origin","secret"],"additionalProperties":false},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"type":{"type":"string","const":"api_key"},"origin":{"type":"string","format":"uri","maxLength":2000},"pathPrefix":{"anyOf":[{"type":"string","maxLength":1000,"default":null},{"type":"null"}]},"secret":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[!#$%&'*+.^_`|~0-9A-Za-z-]+$"},"value":{"type":"string","minLength":1,"maxLength":8192,"writeOnly":true}},"required":["name","value"],"additionalProperties":false,"title":"API key header secret","writeOnly":true}},"required":["name","type","origin","secret"],"additionalProperties":false},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"type":{"type":"string","const":"basic"},"origin":{"type":"string","format":"uri","maxLength":2000},"pathPrefix":{"anyOf":[{"type":"string","maxLength":1000,"default":null},{"type":"null"}]},"secret":{"type":"object","properties":{"username":{"type":"string","maxLength":1000,"writeOnly":true},"password":{"type":"string","maxLength":8192,"writeOnly":true}},"required":["username","password"],"additionalProperties":false,"title":"Basic authentication secret","writeOnly":true}},"required":["name","type","origin","secret"],"additionalProperties":false},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"type":{"type":"string","const":"custom_headers"},"origin":{"type":"string","format":"uri","maxLength":2000},"pathPrefix":{"anyOf":[{"type":"string","maxLength":1000,"default":null},{"type":"null"}]},"secret":{"type":"object","properties":{"headers":{"type":"object","properties":{},"maxProperties":20,"propertyNames":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[!#$%&'*+.^_`|~0-9A-Za-z-]+$"},"additionalProperties":{"type":"string","maxLength":2000},"writeOnly":true}},"required":["headers"],"additionalProperties":false,"title":"Custom header secrets","writeOnly":true}},"required":["name","type","origin","secret"],"additionalProperties":false},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"type":{"type":"string","const":"oauth2"},"origin":{"type":"string","format":"uri","maxLength":2000},"pathPrefix":{"anyOf":[{"type":"string","maxLength":1000,"default":null},{"type":"null"}]},"secret":{"type":"object","properties":{"authorizationUrl":{"type":"string","format":"uri","maxLength":2000},"tokenUrl":{"type":"string","format":"uri","maxLength":2000},"clientId":{"type":"string","minLength":1,"maxLength":1000},"clientSecret":{"type":"string","maxLength":8192,"writeOnly":true},"scopes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":200},"maxItems":30,"default":[]},"accessToken":{"type":"string","maxLength":8192,"writeOnly":true},"refreshToken":{"type":"string","maxLength":8192,"writeOnly":true},"expiresAt":{"type":"string","format":"date-time"}},"required":["authorizationUrl","tokenUrl","clientId"],"additionalProperties":false,"title":"OAuth 2.0 authorization-code secret and provider settings","writeOnly":true}},"required":["name","type","origin","secret"],"additionalProperties":false}]},"AutomationCredentialReplace":{"type":"object","properties":{"expectedVersion":{"type":"integer","minimum":1},"name":{"type":"string","minLength":1,"maxLength":120},"secret":{"oneOf":[{"type":"object","properties":{"token":{"type":"string","minLength":1,"maxLength":8192,"writeOnly":true}},"required":["token"],"additionalProperties":false,"title":"Bearer secret"},{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[!#$%&'*+.^_`|~0-9A-Za-z-]+$"},"value":{"type":"string","minLength":1,"maxLength":8192,"writeOnly":true}},"required":["name","value"],"additionalProperties":false,"title":"API key header secret"},{"type":"object","properties":{"username":{"type":"string","maxLength":1000,"writeOnly":true},"password":{"type":"string","maxLength":8192,"writeOnly":true}},"required":["username","password"],"additionalProperties":false,"title":"Basic authentication secret"},{"type":"object","properties":{"headers":{"type":"object","properties":{},"maxProperties":20,"propertyNames":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[!#$%&'*+.^_`|~0-9A-Za-z-]+$"},"additionalProperties":{"type":"string","maxLength":2000},"writeOnly":true}},"required":["headers"],"additionalProperties":false,"title":"Custom header secrets"},{"type":"object","properties":{"authorizationUrl":{"type":"string","format":"uri","maxLength":2000},"tokenUrl":{"type":"string","format":"uri","maxLength":2000},"clientId":{"type":"string","minLength":1,"maxLength":1000},"clientSecret":{"type":"string","maxLength":8192,"writeOnly":true},"scopes":{"type":"array","items":{"type":"string","minLength":1,"maxLength":200},"maxItems":30,"default":[]},"accessToken":{"type":"string","maxLength":8192,"writeOnly":true},"refreshToken":{"type":"string","maxLength":8192,"writeOnly":true},"expiresAt":{"type":"string","format":"date-time"}},"required":["authorizationUrl","tokenUrl","clientId"],"additionalProperties":false,"title":"OAuth 2.0 authorization-code secret and provider settings"}],"writeOnly":true}},"required":["expectedVersion","secret"],"additionalProperties":false},"StepRun":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"stepId":{"type":"string","format":"uuid"},"position":{"type":"integer","minimum":1},"type":{"type":"string","enum":["webhook","email","http","log"]},"status":{"type":"string","enum":["pending","running","delivered","failed","skipped"]},"output":{"type":"string","maxLength":8192},"log":{"type":"string","maxLength":2000},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"completedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","stepId","position","type","status","output","log","startedAt","completedAt"]},"NodeRun":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"nodeId":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"type":{"type":"string","enum":["trigger","http","webhook","email","log","update_item","condition","switch"]},"status":{"type":"string","enum":["pending","running","delivered","failed","skipped"]},"attempt":{"type":"integer","minimum":0},"output":{"type":"string","maxLength":8192},"log":{"type":"string","maxLength":2000},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"completedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","nodeId","type","status","attempt","output","log","startedAt","completedAt"],"additionalProperties":false},"AutomationRun":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"automationId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"targetType":{"type":"string","enum":["automation","webhook"]},"targetId":{"type":"string","format":"uuid"},"automationVersion":{"anyOf":[{"type":"integer","minimum":1},{"type":"null"}]},"status":{"type":"string","enum":["pending","running","delivered","failed"]},"detail":{"type":"string","maxLength":2000},"createdAt":{"type":"string","format":"date-time"},"startedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"completedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"heartbeatAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]},"attempt":{"type":"integer","minimum":0},"steps":{"type":"array","items":{"$ref":"#/components/schemas/StepRun"},"maxItems":20},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/NodeRun"},"maxItems":50}},"required":["id","workspaceId","automationId","targetType","targetId","automationVersion","status","detail","createdAt","startedAt","completedAt","heartbeatAt","attempt","steps","nodes"]},"OidcIdentity":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"issuer":{"type":"string","format":"uri","maxLength":2048},"subject":{"type":"string","minLength":1,"maxLength":255},"createdAt":{"type":"string","format":"date-time"}},"required":["id","userId","issuer","subject","createdAt"]}}},"security":[{"bearer":[]},{"session":[]}],"tags":[{"name":"Workspaces"},{"name":"Tasks"},{"name":"Structure & fields"},{"name":"Automations"},{"name":"Accounts & admin"},{"name":"Meta"}],"paths":{"/health":{"get":{"summary":"Health probe","tags":["Meta"],"security":[],"servers":[{"url":"/"}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","const":"ok"}},"required":["status"]},"example":{"status":"ok"}}}}}}},"/config":{"get":{"summary":"Public instance configuration","tags":["Meta"],"security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"landingEnabled":{"type":"boolean"},"logo":{"type":"string"},"registrationEnabled":{"type":"boolean"},"setupRequired":{"type":"boolean"},"ssoEnabled":{"type":"boolean"},"aiEnabled":{"type":"boolean"},"passwordResetEnabled":{"type":"boolean"}},"required":["landingEnabled","registrationEnabled","setupRequired","ssoEnabled","aiEnabled","passwordResetEnabled"]}}}}}}},"/openapi.json":{"get":{"summary":"This OpenAPI 3.1 document","tags":["Meta"],"security":[],"responses":{"200":{"description":"OpenAPI JSON document","content":{"application/json":{"schema":{"type":"object","properties":{}}}}}}}},"/auth/setup":{"post":{"summary":"Create the first site administrator","description":"Public only while setup is incomplete. Requires the operator-provided setup token and creates an HttpOnly session.","tags":["Accounts & admin"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"email":{"type":"string","format":"email","maxLength":254},"password":{"type":"string","minLength":12,"maxLength":256,"writeOnly":true},"setupToken":{"type":"string","maxLength":512,"writeOnly":true}},"required":["name","email","password","setupToken"],"additionalProperties":false},"example":{"name":"Administrator","email":"admin@example.test","password":"[REDACTED]","setupToken":"[REDACTED]"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"403":{"description":"Setup not authorized","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Setup not authorized"}}}},"409":{"description":"Setup already completed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Setup already completed"}}}}}}},"/auth/register":{"post":{"summary":"Register an account","description":"Public only when registration is enabled and setup is complete. Creates an HttpOnly session.","tags":["Accounts & admin"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","maxLength":120},"email":{"type":"string","format":"email","maxLength":254},"password":{"type":"string","minLength":12,"maxLength":256,"writeOnly":true}},"required":["name","email","password"],"additionalProperties":false},"example":{"name":"Example User","email":"user@example.test","password":"[REDACTED]"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"403":{"description":"Registration is closed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Registration is closed"}}}}}}},"/auth/login":{"post":{"summary":"Password sign-in","tags":["Accounts & admin"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":254},"password":{"type":"string","minLength":1,"maxLength":256,"writeOnly":true}},"required":["email","password"],"additionalProperties":false},"example":{"email":"user@example.test","password":"[REDACTED]"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Invalid email or password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid email or password"}}}}}}},"/auth/forgot-password":{"post":{"summary":"Request local password recovery","description":"Always returns the same accepted response for valid email syntax. Delivery is available only when SMTP_URL and SMTP_FROM are configured.","tags":["Accounts & admin"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":254}},"required":["email"],"additionalProperties":false},"example":{"email":"user@example.test"}}}},"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"429":{"description":"Too many authentication attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Too many authentication attempts"}}}}}}},"/auth/reset-password":{"post":{"summary":"Complete local password recovery","description":"Consumes a single-use 30-minute token and revokes all sessions and personal access tokens.","tags":["Accounts & admin"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":43,"maxLength":43,"writeOnly":true},"password":{"type":"string","minLength":12,"maxLength":256,"writeOnly":true}},"required":["token","password"],"additionalProperties":false},"example":{"token":"[REDACTED]","password":"[REDACTED]"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}},"required":["success"]}}}},"400":{"description":"Password reset link is invalid or expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Password reset link is invalid or expired"}}}},"429":{"description":"Too many authentication attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Too many authentication attempts"}}}}}}},"/auth/sso":{"get":{"summary":"Start an optional OIDC sign-in","description":"Creates a short-lived HttpOnly PKCE flow cookie and redirects to the operator-configured issuer. No local account is selected by unverified email.","tags":["Accounts & admin"],"security":[],"responses":{"302":{"description":"Redirect to the configured OIDC authorization endpoint"},"429":{"description":"Too many SSO attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Too many SSO attempts"}}}},"503":{"description":"SSO is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"SSO is not configured"}}}}}}},"/auth/sso/callback":{"get":{"summary":"Complete an optional OIDC sign-in","description":"Validates and consumes the PKCE flow, then binds the verified issuer/subject identity. Auto-provisioning is separate and disabled by default.","tags":["Accounts & admin"],"security":[],"parameters":[{"name":"code","in":"query","required":false,"schema":{"type":"string"}},{"name":"state","in":"query","required":false,"schema":{"type":"string","maxLength":256}},{"name":"error","in":"query","required":false,"schema":{"type":"string"}}],"responses":{"302":{"description":"Redirect to the authenticated application"},"401":{"description":"SSO authentication failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"SSO authentication failed"}}}},"403":{"description":"SSO identity is not linked to an account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"SSO identity is not linked to an account"}}}},"409":{"description":"SSO account requires administrator linking","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"SSO account requires administrator linking"}}}},"503":{"description":"SSO is not configured","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"SSO is not configured"}}}}}}},"/auth/logout":{"post":{"summary":"Sign out and revoke the current session","description":"Requires an authenticated account.","tags":["Accounts & admin"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Authentication required"}}}}}}},"/auth/me":{"get":{"summary":"Current user","description":"Requires an authenticated account.","tags":["Accounts & admin"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Authentication required"}}}}}}},"/auth/profile":{"patch":{"summary":"Update profile or credentials","description":"Requires authentication. Email and password changes require currentPassword and revoke other sessions and tokens.","tags":["Accounts & admin"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"email":{"type":"string","format":"email","maxLength":254},"password":{"type":"string","minLength":12,"maxLength":256,"writeOnly":true},"currentPassword":{"type":"string","minLength":1,"maxLength":256,"writeOnly":true}},"required":["name"],"additionalProperties":false},"example":{"name":"Example User","email":"user@example.test"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"400":{"description":"Invalid profile update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid profile update"}}}},"403":{"description":"Current password is incorrect","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Current password is incorrect"}}}},"409":{"description":"Account changed or email is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Account changed or email is unavailable"}}}}}}},"/auth/tokens":{"get":{"summary":"List API token metadata","description":"Requires an authenticated account.","tags":["Accounts & admin"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"}},"required":["id","name","createdAt","expiresAt"]}}}}}}},"post":{"summary":"Create an API token","description":"Requires authentication. The raw token is returned once and only its hash is stored.","tags":["Accounts & admin"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120}},"required":["name"],"additionalProperties":false},"example":{"name":"CLI on workstation"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","writeOnly":true}},"required":["token"]},"example":{"token":"[REDACTED]"}}}},"409":{"description":"Maximum active tokens reached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Maximum active tokens reached"}}}}}}},"/auth/tokens/{id}":{"delete":{"summary":"Revoke an API token","description":"Requires an authenticated account.","tags":["Accounts & admin"],"parameters":[{"name":"id","in":"path","required":true,"description":"Token ID owned by the current account.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Token not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Token not found"}}}}}}},"/admin/users":{"get":{"summary":"List accounts","description":"Requires site administrator.","tags":["Accounts & admin"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AdminUser"}}}}},"403":{"description":"Site administrator required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Site administrator required"}}}}}},"post":{"summary":"Create an account","description":"Requires site administrator.","tags":["Accounts & admin"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"email":{"type":"string","format":"email","maxLength":254},"password":{"type":"string","minLength":12,"maxLength":256,"writeOnly":true},"isAdmin":{"type":"boolean","default":false}},"required":["name","email","password"],"additionalProperties":false},"example":{"name":"Example User","email":"user@example.test","password":"[REDACTED]","isAdmin":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUser"}}}},"403":{"description":"Site administrator required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Site administrator required"}}}}}}},"/admin/users/{id}":{"patch":{"summary":"Change account admin or disabled flags","description":"Requires site administrator. Disabling revokes credentials and clears task assignments; the last active administrator is protected.","tags":["Accounts & admin"],"parameters":[{"name":"id","in":"path","required":true,"description":"Target user ID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"isAdmin":{"type":"boolean"},"disabled":{"type":"boolean"}},"additionalProperties":false,"minProperties":1},"example":{"disabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AdminUser"}}}},"404":{"description":"User not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"User not found"}}}},"409":{"description":"Site must retain an active administrator","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Site must retain an active administrator"}}}}}}},"/admin/audit":{"get":{"summary":"Audit log","description":"Requires site administrator. Audit details are sanitized and do not include raw secrets or full AI prompts.","tags":["Accounts & admin"],"parameters":[{"name":"workspaceId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"maximum":1000000,"default":0}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}}}}}}},"/admin/status":{"get":{"summary":"Instance status","description":"Requires site administrator.","tags":["Accounts & admin"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}}}}},"/admin/oidc-identities":{"get":{"summary":"List linked OIDC identities","description":"Requires site administrator. Returns issuer and subject binding metadata, never provider tokens.","tags":["Accounts & admin"],"parameters":[{"name":"userId","in":"query","required":false,"description":"Optional exact user filter.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OidcIdentity"}}}}},"403":{"description":"Site administrator required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Site administrator required"}}}}}},"post":{"summary":"Link an OIDC identity to an active account","description":"Requires site administrator. Identity ownership is bound to exact issuer and subject, not email.","tags":["Accounts & admin"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"issuer":{"type":"string","format":"uri","minLength":1,"maxLength":2048},"subject":{"type":"string","minLength":1,"maxLength":255}},"required":["userId","issuer","subject"],"additionalProperties":false},"example":{"userId":"11111111-1111-4111-8111-111111111111","issuer":"https://id.example.test","subject":"provider-subject-123"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","userId","createdAt"]}}}},"400":{"description":"Invalid OIDC identity","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid OIDC identity"}}}},"404":{"description":"Active user not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Active user not found"}}}},"409":{"description":"OIDC identity already linked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"OIDC identity already linked"}}}}}}},"/admin/oidc-identities/{id}":{"delete":{"summary":"Unlink an OIDC identity","description":"Requires site administrator. Revokes all sessions and tokens for the target account and preserves its last configured login method.","tags":["Accounts & admin"],"parameters":[{"name":"id","in":"path","required":true,"description":"OIDC identity ID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"OIDC identity not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"OIDC identity not found"}}}},"409":{"description":"Cannot remove the last login method","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Cannot remove the last login method"}}}}}}},"/site/settings":{"get":{"summary":"Read site settings","description":"Requires site administrator.","tags":["Accounts & admin"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"landingDisabled":{"type":"boolean"},"mcpSseEnabled":{"type":"boolean"},"logo":{"anyOf":[{"type":"object","properties":{"updatedAt":{"type":"string","format":"date-time"},"url":{"type":"string"}},"required":["updatedAt","url"]},{"type":"null"}]}},"required":["landingDisabled","mcpSseEnabled","logo"]}}}}}},"patch":{"summary":"Update site settings","description":"Requires site administrator. Disabling MCP SSE closes active sessions.","tags":["Accounts & admin"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"landingDisabled":{"type":"boolean"},"mcpSseEnabled":{"type":"boolean"}},"additionalProperties":false,"minProperties":1},"example":{"mcpSseEnabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"landingDisabled":{"type":"boolean"},"mcpSseEnabled":{"type":"boolean"}},"required":["landingDisabled","mcpSseEnabled"]}}}},"403":{"description":"Site administrator required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Site administrator required"}}}}}}},"/mcp/sse":{"get":{"summary":"Open MCP SSE transport","description":"Disabled by default and enabled by a site administrator. Requires a personal bearer token; browser session cookies are not accepted. Sessions expire after 30 minutes.","tags":["Integrations"],"security":[{"bearer":[]}],"responses":{"200":{"description":"MCP server-sent event stream","content":{"text/event-stream":{"schema":{"type":"string"}}}},"401":{"description":"Bearer token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Bearer token required"}}}},"404":{"description":"MCP SSE disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"MCP SSE disabled"}}}},"429":{"description":"Too many MCP sessions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Too many MCP sessions"}}}}}}},"/mcp/messages":{"post":{"summary":"Send an MCP SSE session message","description":"Requires the same authenticated user as the SSE session. Token validity and account state are rechecked for every message.","tags":["Integrations"],"security":[{"bearer":[]}],"parameters":[{"name":"sessionId","in":"query","required":false,"description":"Session identifier supplied by the MCP SSE endpoint event.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}},"responses":{"202":{"description":"MCP message accepted"},"400":{"description":"Invalid MCP message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid MCP message"}}}},"401":{"description":"Bearer token required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Bearer token required"}}}},"404":{"description":"MCP session not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"MCP session not found"}}}}}}},"/site/logo":{"get":{"summary":"Read custom logo bytes","tags":["Accounts & admin"],"security":[],"responses":{"200":{"description":"PNG, JPEG, WebP, or SVG bytes"},"404":{"description":"No custom logo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"No custom logo"}}}}}},"put":{"summary":"Upload custom logo","description":"Requires site administrator. Base64-decoded content is limited to 300 KiB and to PNG, JPEG, WebP, or SVG.","tags":["Accounts & admin"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"contentType":{"type":"string","enum":["image/png","image/jpeg","image/webp","image/svg+xml"]},"data":{"type":"string","format":"byte","writeOnly":true}},"required":["contentType","data"],"additionalProperties":false},"example":{"contentType":"image/png","data":"[BASE64 IMAGE DATA]"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"}},"required":["url","updatedAt"]}}}},"400":{"description":"Invalid logo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid logo"}}}},"403":{"description":"Site administrator required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Site administrator required"}}}}}},"delete":{"summary":"Remove custom logo","description":"Requires site administrator.","tags":["Accounts & admin"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"No custom logo","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"No custom logo"}}}}}}},"/workspaces":{"get":{"summary":"List workspace memberships","description":"Requires an authenticated account.","tags":["Workspaces"],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{},"additionalProperties":true}}}}}}},"post":{"summary":"Create a workspace","description":"Requires authentication. The creator receives the protected Owner role.","tags":["Workspaces"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120}},"required":["name"],"additionalProperties":false},"example":{"name":"Product planning"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"403":{"description":"Account unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Account unavailable"}}}}}}},"/workspaces/{wid}":{"get":{"summary":"Workspace detail and authorized metadata","description":"Requires workspace membership. Metadata arrays are permission-filtered.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}},"403":{"description":"Workspace access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Workspace access denied"}}}}}},"patch":{"summary":"Rename a workspace","description":"Requires the workspace `workspace:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120}},"required":["name"],"additionalProperties":false},"example":{"name":"Product operations"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"403":{"description":"Permission denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Permission denied"}}}}}},"delete":{"summary":"Permanently delete a workspace","description":"Requires the protected Owner role. All relational workspace contents are deleted atomically; detached storage objects enter the existing garbage-collection lifecycle.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"403":{"description":"Workspace owner required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Workspace owner required"}}}}}}},"/workspaces/{wid}/export":{"get":{"summary":"Stream complete workspace export","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Complete versioned JSON export; attachment metadata only, never attachment bytes or secrets","content":{"application/json":{"schema":{"type":"object","properties":{},"additionalProperties":true}}}}}}},"/workspaces/{wid}/nodes":{"get":{"summary":"List hierarchy nodes","description":"Requires items:read or structure:write.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Node"}}}}}}},"post":{"summary":"Create a project, folder, or list","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. Projects and standalone lists may use a null parent; folders and nested lists require a project or folder parent.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodeCreate"},"example":{"name":"Release backlog","kind":"list","parentId":null,"icon":"checklist","color":"#c45d0a"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Node"}}}},"400":{"description":"Invalid hierarchy placement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid hierarchy placement"}}}},"403":{"description":"Permission denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Permission denied"}}}}}}},"/workspaces/{wid}/nodes/{id}":{"patch":{"summary":"Rename, move, or style a node","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. Lists may move to workspace root; inherited statuses are materialized first. Other moves reject cycles, cross-workspace parents, incompatible inherited statuses, and hierarchy depth above 32.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Node ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/NodePatch"},"example":{"name":"Ready for review","icon":"sparkles","color":"#4d7a47"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Node"}}}},"400":{"description":"Invalid node update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid node update"}}}},"404":{"description":"Node not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Node not found"}}}},"409":{"description":"Location changed; reload before moving","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Location changed; reload before moving"}}}}}},"delete":{"summary":"Delete an empty node","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Node ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Node not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Node not found"}}}},"409":{"description":"Node must be empty before deletion","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Node must be empty before deletion"}}}}}}},"/workspaces/{wid}/documents":{"get":{"summary":"List document hierarchy metadata","description":"Requires document read/write or structure management access. Bodies are omitted.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"parentDocumentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"pagePlacement":{"anyOf":[{"type":"string","enum":["page","subpage"]},{"type":"null"}]},"title":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","workspaceId","parentId","parentDocumentId","pagePlacement","title","createdAt","updatedAt"]}}}}}}},"post":{"summary":"Create a document","description":"Requires the workspace `documents:write` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300},"body":{"type":"string","maxLength":50000},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]}},"required":["title"],"additionalProperties":false},"example":{"title":"Runbook","body":"Start here.","parentId":null}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"400":{"description":"Invalid document placement","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid document placement"}}}}}}},"/workspaces/{wid}/documents/{id}":{"get":{"summary":"Read a document","description":"Requires the workspace `documents:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"404":{"description":"Document not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Document not found"}}}}}},"patch":{"summary":"Update a document","description":"Requires documents:read and documents:write.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300},"body":{"type":"string","maxLength":50000},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"expectedUpdatedAt":{"type":"string","format":"date-time"}},"required":["expectedUpdatedAt"],"additionalProperties":false},"example":{"body":"Updated body","expectedUpdatedAt":"2026-09-10T00:00:00.000Z"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}},"409":{"description":"Document changed; reload before saving","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Document changed; reload before saving"}}}}}},"delete":{"summary":"Delete a document and its document subpages","description":"Requires documents:delete. Nested document pages are deleted; linked tasks and task subtasks are preserved.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"unlinkedPages":{"type":"integer","minimum":0},"deletedSubpages":{"type":"integer","minimum":0}},"required":["success","unlinkedPages","deletedSubpages"]}}}}}}},"/workspaces/{wid}/documents/{id}/pages":{"get":{"summary":"List a bounded document task-page tree","description":"Requires documents:read and items:read. At most 500 complete tasks are rendered; total remains complete.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Item"},"maxItems":500},"total":{"type":"integer","minimum":0},"truncated":{"type":"boolean"}},"required":["items","total","truncated"]}}}}}},"post":{"summary":"Link a top-level task as a document page","description":"Requires documents:write and items:read. A task may be linked to only one document.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","format":"uuid"},"position":{"type":"integer","minimum":0,"maximum":1000000}},"required":["itemId"],"additionalProperties":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"documentId":{"type":"string","format":"uuid"},"itemId":{"type":"string","format":"uuid"},"position":{"type":"integer"}},"required":["documentId","itemId","position"]}}}},"409":{"description":"Task is already linked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Task is already linked"}}}}}}},"/workspaces/{wid}/documents/{id}/subpages":{"get":{"summary":"List editable document pages","description":"Requires documents:read. Returns up to 500 document pages under the containing root document while preserving the complete total.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"rootId":{"type":"string","format":"uuid"},"documents":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"workspaceId":{"type":"string","format":"uuid"},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"parentDocumentId":{"type":"string","format":"uuid"},"pagePlacement":{"type":"string","enum":["page","subpage"]},"title":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","workspaceId","parentId","parentDocumentId","pagePlacement","title","createdAt","updatedAt"]},"maxItems":500},"total":{"type":"integer","minimum":0},"truncated":{"type":"boolean"}},"required":["rootId","documents","total","truncated"]}}}}}},"post":{"summary":"Create an editable document page","description":"Requires documents:write. Placement `page` creates a top-level page from the root document; `subpage` creates beneath the addressed document/page, up to 31 page levels.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":300},"placement":{"type":"string","enum":["page","subpage"]}},"required":["title"],"additionalProperties":false},"example":{"title":"New page","placement":"page"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Document"}}}}}}},"/workspaces/{wid}/documents/{id}/pages/{itemId}":{"delete":{"summary":"Unlink a document page without deleting its task","description":"Requires documents:write and items:read.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}}}}},"/workspaces/{wid}/documents/{id}/comments":{"get":{"summary":"List document comments","description":"Requires the workspace `documents:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}}}}}},"post":{"summary":"Add a document comment, reply, or inline thread","description":"Requires documents:read and comments:create. Anchors are revision-checked UTF-16 ranges over the Markdown body.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"anchor":{"$ref":"#/components/schemas/CommentAnchorInput"}},"required":["body"],"additionalProperties":false}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"409":{"description":"Selected text is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Selected text is stale"}}}}}}},"/workspaces/{wid}/documents/{id}/comments/{commentId}":{"delete":{"summary":"Delete or purge a document comment","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"commentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}}}}},"/workspaces/{wid}/documents/{id}/comments/{commentId}/reaction":{"patch":{"summary":"Add or remove a document comment reaction","description":"Requires documents:read and comments:create.","tags":["Documents"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"}},{"name":"commentId","in":"path","required":true,"schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"emoji":{"type":"string","enum":["👍","❤️","😂","🎉","😕","👀"]},"active":{"type":"boolean"}},"required":["emoji","active"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"emoji":{"type":"string"},"active":{"type":"boolean"},"count":{"type":"integer"}},"required":["emoji","active","count"]}}}}}}},"/workspaces/{wid}/items":{"get":{"summary":"Stream all matching tasks","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"nodeId","in":"query","required":false,"description":"Exact list ID.","schema":{"type":"string","format":"uuid"}},{"name":"search","in":"query","required":false,"description":"Title/description search.","schema":{"type":"string","maxLength":300}},{"name":"status","in":"query","required":false,"description":"Exact effective status ID.","schema":{"type":"string","maxLength":64}},{"name":"archived","in":"query","required":false,"description":"Archived-task visibility.","schema":{"type":"string","enum":["exclude","include","only"],"default":"exclude"}}],"responses":{"200":{"description":"Complete JSON task array streamed from a bounded-lifetime snapshot","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Item"}}}}}}},"post":{"summary":"Create a task","description":"Requires the workspace `items:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. nodeId must be a list and status must belong to its effective workflow.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemCreate"},"example":{"nodeId":"33333333-3333-4333-8333-333333333333","title":"Prepare release notes","priority":"high","tags":["release"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"400":{"description":"Invalid task","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid task"}}}},"404":{"description":"Node or parent task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Node or parent task not found"}}}}}}},"/workspaces/{wid}/items/page":{"get":{"summary":"Cursor-paged tasks","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"nodeId","in":"query","required":false,"description":"Exact list ID.","schema":{"type":"string","format":"uuid"}},{"name":"search","in":"query","required":false,"description":"Title/description search.","schema":{"type":"string","maxLength":300}},{"name":"status","in":"query","required":false,"description":"Exact effective status ID.","schema":{"type":"string","maxLength":64}},{"name":"archived","in":"query","required":false,"description":"Archived-task visibility.","schema":{"type":"string","enum":["exclude","include","only"],"default":"exclude"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":500,"default":200}},{"name":"cursor","in":"query","required":false,"description":"Opaque cursor bound to workspace and active filters; it is not a credential.","schema":{"type":"string","minLength":1,"maxLength":1024}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Item"}},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["items","nextCursor"]}}}},"400":{"description":"Invalid item cursor","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid item cursor"}}}}}}},"/workspaces/{wid}/items/bulk":{"post":{"summary":"Archive or delete selected tasks atomically","description":"Archive requires items:read and items:write; delete requires items:delete. Every target revision is checked and parent tasks require all subtasks in the same selection.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["archive","delete"]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"expectedUpdatedAt":{"type":"string","format":"date-time"}},"required":["id","expectedUpdatedAt"],"additionalProperties":false},"minItems":1,"maxItems":100,"uniqueItems":true}},"required":["action","items"],"additionalProperties":false},"example":{"action":"archive","items":[{"id":"33333333-3333-4333-8333-333333333333","expectedUpdatedAt":"2026-09-08T10:00:00.000Z"}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"action":{"type":"string","enum":["archive","delete"]},"affected":{"type":"integer","minimum":1,"maximum":100}},"required":["action","affected"]}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Task not found"}}}},"409":{"description":"A task changed or has unselected subtasks","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"A task changed or has unselected subtasks"}}}}}}},"/workspaces/{wid}/items/import":{"post":{"summary":"Import tasks atomically from JSON or CSV","description":"Requires the workspace `items:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. Maximum 500 rows and 1,000,000 characters; a row failure rolls back the whole import.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"nodeId":{"type":"string","format":"uuid"},"format":{"type":"string","enum":["json","csv"]},"data":{"type":"string","maxLength":1000000}},"required":["nodeId","format","data"],"additionalProperties":false},"example":{"nodeId":"33333333-3333-4333-8333-333333333333","format":"json","data":"[{\"title\":\"Imported task\",\"priority\":\"medium\"}]"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"imported":{"type":"integer","minimum":0,"maximum":500},"ids":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":500}},"required":["imported","ids"]}}}},"400":{"description":"Import validation failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Import validation failed"}}}}}}},"/workspaces/{wid}/items/export":{"get":{"summary":"Export tasks as JSON or CSV","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["json","csv"],"default":"json"}},{"name":"nodeId","in":"query","required":false,"schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","maxLength":64}},{"name":"search","in":"query","required":false,"schema":{"type":"string","maxLength":300}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":5000,"default":1000}}],"responses":{"200":{"description":"Task array or CSV attachment"}}}},"/workspaces/{wid}/items/{id}":{"get":{"summary":"Get a task","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Task not found"}}}}}},"patch":{"summary":"Update a task","description":"Requires both items:read and items:write. Optional expectedUpdatedAt provides optimistic concurrency; omitted means last-write-wins.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ItemPatch"},"example":{"title":"Prepare final release notes","expectedUpdatedAt":"2026-09-08T10:00:00.000Z"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Item"}}}},"400":{"description":"Invalid task update","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid task update"}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Task not found"}}}},"409":{"description":"Item changed; reload before saving","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Item changed; reload before saving"}}}}}},"delete":{"summary":"Delete a task","description":"Requires the workspace `items:delete` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Task not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Task not found"}}}},"409":{"description":"Task has subtasks and cannot be deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Task has subtasks and cannot be deleted"}}}}}}},"/workspaces/{wid}/items/{id}/comments":{"get":{"summary":"List task comments","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Comment"}}}}}}},"post":{"summary":"Add a task comment, reply, or inline thread","description":"Requires items:read and comments:create. Optional parentId must identify a comment on this task. Anchors are revision-checked UTF-16 ranges over the task description.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":10000},"parentId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"anchor":{"$ref":"#/components/schemas/CommentAnchorInput"}},"required":["body"],"additionalProperties":false},"example":{"body":"Please review this task.","parentId":null}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Comment"}}}},"400":{"description":"Invalid comment, reply depth, or mention","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid comment, reply depth, or mention"}}}},"404":{"description":"Task or parent comment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Task or parent comment not found"}}}},"409":{"description":"Selected text is stale","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Selected text is stale"}}}}}}},"/workspaces/{wid}/items/{id}/comments/{commentId}":{"delete":{"summary":"Delete a comment or remove its tombstone","description":"The author or comments:manage may replace a live comment with a tombstone. A subsequent call requires comments:manage and permanently removes that deleted entry while preserving its replies.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}},{"name":"commentId","in":"path","required":true,"description":"Comment ID on this task.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"403":{"description":"Comment author or comments manager required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Comment author or comments manager required"}}}},"404":{"description":"Comment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Comment not found"}}}}}}},"/workspaces/{wid}/items/{id}/comments/{commentId}/reaction":{"patch":{"summary":"Add or remove the current member reaction","description":"Requires items:read and comments:create. Reactions are unique per member, comment, and emoji.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}},{"name":"commentId","in":"path","required":true,"description":"Comment ID on this task.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"emoji":{"type":"string","enum":["👍","❤️","😂","🎉","😕","👀"]},"active":{"type":"boolean"}},"required":["emoji","active"],"additionalProperties":false},"example":{"emoji":"👍","active":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"emoji":{"type":"string"},"active":{"type":"boolean"},"count":{"type":"integer","minimum":0}},"required":["emoji","active","count"]}}}},"404":{"description":"Comment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Comment not found"}}}},"409":{"description":"Deleted comments cannot receive reactions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Deleted comments cannot receive reactions"}}}}}}},"/workspaces/{wid}/notifications":{"get":{"summary":"List the current member notifications","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Notification"}}}}}}}},"/workspaces/{wid}/notifications/unread-count":{"get":{"summary":"Count the current member unread notifications","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"unread":{"type":"integer","minimum":0}},"required":["unread"]}}}}}}},"/workspaces/{wid}/notifications/{id}":{"patch":{"summary":"Mark an owned notification read or unread","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Notification ID owned by the current member.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"read":{"type":"boolean"}},"required":["read"],"additionalProperties":false},"example":{"read":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"readAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["id","readAt"]}}}},"404":{"description":"Notification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Notification not found"}}}}}},"delete":{"summary":"Delete an owned notification","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Notification ID owned by the current member.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Notification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Notification not found"}}}}}}},"/workspaces/{wid}/fields":{"get":{"summary":"List workspace field definitions","description":"Requires items:read or structure:write.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Field"}}}}}}},"post":{"summary":"Create a field definition","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. Optional projectId identifies a root project or standalone list and creates the assignment atomically.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FieldCreate"},"example":{"name":"Effort","type":"rating","settings":{"maxRating":5}}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Field"}}}},"400":{"description":"Invalid field definition","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid field definition"}}}}}}},"/workspaces/{wid}/fields/{id}":{"patch":{"summary":"Update a field definition","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. Field type cannot change; updates that invalidate stored values or formula references are rejected.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Field ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/FieldPatch"},"example":{"name":"Delivery effort","settings":{"maxRating":5}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Field"}}}},"404":{"description":"Field not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Field not found"}}}},"409":{"description":"Field update conflicts with stored values or formulas","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Field update conflicts with stored values or formulas"}}}}}},"delete":{"summary":"Delete a field and its values","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. Also removes assignments and task values; referenced fields cannot be deleted.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Field ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Field not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Field not found"}}}},"409":{"description":"Field is referenced by a formula","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Field is referenced by a formula"}}}}}}},"/workspaces/{wid}/projects/{projectId}/fields":{"get":{"summary":"Read field-owner configuration","description":"Requires items:read or structure:write. The target must be a root project or standalone root list.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"projectId","in":"path","required":true,"description":"Root project or standalone list ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectFields"}}}}}},"patch":{"summary":"Update fields, workflow, or date format","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. The target may be a root project or standalone list. Standalone workflows remain managed by the list-status endpoint. Optional expectedUpdatedAt protects against concurrent updates; project statuses in use cannot be removed. Null dateFormat restores the default.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"projectId","in":"path","required":true,"description":"Root project or standalone list ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"fieldIds":{"type":"array","items":{"type":"string","format":"uuid"},"maxItems":100,"uniqueItems":true},"builtInFields":{"type":"array","items":{"type":"string","enum":["priority","startDate","tags","description","nodeId","createdAt","updatedAt"]},"maxItems":7,"uniqueItems":true},"statuses":{"type":"array","items":{"$ref":"#/components/schemas/Status"},"minItems":1,"maxItems":50},"dateFormat":{"anyOf":[{"type":"string","enum":["yyyy-MM-dd","MMM d, yyyy","MMMM d, yyyy","dd/MM/yyyy"]},{"type":"null"}]},"expectedUpdatedAt":{"type":"string","format":"date-time"}},"additionalProperties":false,"anyOf":[{"required":["fieldIds"]},{"required":["builtInFields"]},{"required":["statuses"]},{"required":["dateFormat"]}]},"example":{"builtInFields":["priority","tags"],"expectedUpdatedAt":"2026-09-08T10:00:00.000Z"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectFields"}}}},"400":{"description":"Invalid field-owner configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid field-owner configuration"}}}},"409":{"description":"Field configuration changed or statuses remain in use","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Field configuration changed or statuses remain in use"}}}}}}},"/workspaces/{wid}/views/list/settings":{"get":{"summary":"Read the authenticated member's List settings","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"projectId","in":"query","required":false,"description":"Root project or standalone-list field scope; omit for workspace-wide scope.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListViewSettings"}}}}}},"patch":{"summary":"Replace the authenticated member's List settings","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user. Identity always comes from authentication. expectedUpdatedAt must be null when creating or exactly match the stored revision.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}]},"columnOrder":{"type":"array","items":{"type":"string","maxLength":43},"maxItems":111,"uniqueItems":true},"hiddenColumns":{"type":"array","items":{"type":"string","maxLength":43},"maxItems":110,"uniqueItems":true},"sort":{"anyOf":[{"type":"object","properties":{"column":{"type":"string","maxLength":43},"direction":{"type":"string","enum":["asc","desc"]}},"required":["column","direction"],"additionalProperties":false},{"type":"null"}]},"expectedUpdatedAt":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}]}},"required":["columnOrder","hiddenColumns","sort","expectedUpdatedAt"],"additionalProperties":false},"example":{"projectId":null,"columnOrder":["title","status","dueDate"],"hiddenColumns":[],"sort":{"column":"dueDate","direction":"asc"},"expectedUpdatedAt":null}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListViewSettings"}}}},"400":{"description":"Invalid List settings","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid List settings"}}}},"409":{"description":"List view settings changed; reload before saving","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"List view settings changed; reload before saving"}}}}}}},"/workspaces/{wid}/lists/{listId}/statuses":{"get":{"summary":"Read a list workflow override or inheritance state","description":"Requires items:read or structure:write. Standalone root lists always return explicit statuses and omit inheritedProjectUpdatedAt.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"listId","in":"path","required":true,"description":"List ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListStatuses"}}}}}},"patch":{"summary":"Set or clear a list workflow override","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. null restores project inheritance and is invalid for a standalone root list. Enabling an override from inheritance requires the current project revision.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"listId","in":"path","required":true,"description":"List ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"statuses":{"anyOf":[{"type":"array","items":{"$ref":"#/components/schemas/Status"},"minItems":1,"maxItems":50},{"type":"null"}]},"expectedUpdatedAt":{"type":"string","format":"date-time"},"expectedProjectUpdatedAt":{"type":"string","format":"date-time"}},"required":["statuses"],"additionalProperties":false},"example":{"statuses":null,"expectedUpdatedAt":"2026-09-08T10:00:00.000Z"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListStatuses"}}}},"400":{"description":"Invalid list workflow","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid list workflow"}}}},"409":{"description":"List or project statuses changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"List or project statuses changed"}}}}}}},"/workspaces/{wid}/lists/{listId}/tag-colors":{"get":{"summary":"Read per-list tag colors","description":"Requires items:read or structure:write.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"listId","in":"path","required":true,"description":"List ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagColors"}}}}}},"patch":{"summary":"Replace per-list tag colors","description":"Requires the workspace `structure:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. Up to 30 trimmed tag names map to six-digit hex colors. expectedUpdatedAt is mandatory.","tags":["Structure & fields"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"listId","in":"path","required":true,"description":"List ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"colors":{"type":"object","properties":{},"maxProperties":30,"additionalProperties":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","example":"#2f7d32"}},"expectedUpdatedAt":{"type":"string","format":"date-time"}},"required":["colors","expectedUpdatedAt"],"additionalProperties":false},"example":{"colors":{"release":"#e36b24","blocked":"#b42318"},"expectedUpdatedAt":"2026-09-08T10:00:00.000Z"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListTagColors"}}}},"400":{"description":"Invalid tag color map","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid tag color map"}}}},"409":{"description":"List tag colors changed; reload before saving","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"List tag colors changed; reload before saving"}}}}}}},"/workspaces/{wid}/members":{"post":{"summary":"Add an existing active account to a workspace","description":"Requires the workspace `members:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. The actor cannot grant permissions they do not hold.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email","maxLength":254},"roleId":{"type":"string","format":"uuid"}},"required":["email","roleId"],"additionalProperties":false},"example":{"email":"member@example.test","roleId":"44444444-4444-4444-8444-444444444444"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Membership"}}}},"403":{"description":"Permission denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Permission denied"}}}},"404":{"description":"Active user not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Active user not found"}}}}}}},"/workspaces/{wid}/members/{userId}":{"patch":{"summary":"Change a member role","description":"Requires the workspace `members:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. Permission escalation and removal of the last active Owner are rejected.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"description":"Member user ID.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"roleId":{"type":"string","format":"uuid"}},"required":["roleId"],"additionalProperties":false},"example":{"roleId":"44444444-4444-4444-8444-444444444444"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Membership"}}}},"404":{"description":"Member not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Member not found"}}}},"409":{"description":"Workspace must retain an active Owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Workspace must retain an active Owner"}}}}}},"delete":{"summary":"Remove a workspace member","description":"Requires the workspace `members:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. Clears this member's assignments and protects the last active Owner.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"description":"Member user ID.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Member not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Member not found"}}}},"409":{"description":"Workspace must retain an active Owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Workspace must retain an active Owner"}}}}}}},"/workspaces/{wid}/roles":{"get":{"summary":"List roles visible to the caller","description":"Requires workspace membership; the catalog is permission-filtered.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Role"}}}}}}},"post":{"summary":"Create a role","description":"Requires the workspace `roles:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. The actor cannot grant permissions they do not hold.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"permissions":{"type":"array","items":{"type":"string","enum":["items:read","items:write","items:delete","documents:read","documents:write","documents:delete","comments:create","comments:manage","structure:write","members:manage","roles:manage","workspace:manage","automations:manage","credentials:manage","agent:use"]},"maxItems":15,"uniqueItems":true}},"required":["name","permissions"],"additionalProperties":false},"example":{"name":"Editor","permissions":["items:read","items:write"]}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Role"}}}},"403":{"description":"Permission denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Permission denied"}}}}}}},"/workspaces/{wid}/roles/{id}":{"patch":{"summary":"Update a role","description":"Requires the workspace `roles:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. The Owner role is protected and permission escalation is rejected.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Role ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"permissions":{"type":"array","items":{"type":"string","enum":["items:read","items:write","items:delete","documents:read","documents:write","documents:delete","comments:create","comments:manage","structure:write","members:manage","roles:manage","workspace:manage","automations:manage","credentials:manage","agent:use"]},"maxItems":15,"uniqueItems":true}},"additionalProperties":false},"example":{"permissions":["items:read","items:write"]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Role"}}}},"403":{"description":"Owner role is protected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Owner role is protected"}}}},"404":{"description":"Role not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Role not found"}}}}}},"delete":{"summary":"Delete an unassigned role","description":"Requires the workspace `roles:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. The Owner role is protected.","tags":["Workspaces"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Role ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"403":{"description":"Owner role is protected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Owner role is protected"}}}},"409":{"description":"Role is assigned to members","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Role is assigned to members"}}}}}}},"/workspaces/{wid}/webhooks":{"get":{"summary":"List webhooks","description":"Requires the workspace `workspace:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}}}}}}},"post":{"summary":"Create a webhook","description":"Requires the workspace `workspace:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. Maximum 20 per workspace. The signing secret is returned once and never appears in list responses.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","format":"uri","maxLength":2000},"events":{"type":"array","items":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"minItems":1,"maxItems":7},"enabled":{"type":"boolean","default":true}},"required":["name","url","events"],"additionalProperties":false},"example":{"name":"Issue mirror","url":"https://hooks.example.test/hopya","events":["item.created"],"enabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Webhook"},{"type":"object","properties":{"secret":{"type":"string","writeOnly":true}},"required":["secret"]}]},"example":{"id":"55555555-5555-4555-8555-555555555555","name":"Issue mirror","url":"https://hooks.example.test/hopya","events":["item.created"],"enabled":true,"signingVersion":2,"secret":"[REDACTED]","createdAt":"2026-09-08T10:00:00.000Z","updatedAt":"2026-09-08T10:00:00.000Z"}}}},"400":{"description":"Invalid webhook","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid webhook"}}}}}}},"/workspaces/{wid}/webhooks/{id}":{"patch":{"summary":"Update a webhook","description":"Requires the workspace `workspace:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Webhook ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"url":{"type":"string","format":"uri","maxLength":2000},"events":{"type":"array","items":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"minItems":1,"maxItems":7},"enabled":{"type":"boolean"}},"additionalProperties":false},"example":{"enabled":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Webhook not found"}}}}}},"delete":{"summary":"Delete a webhook and its run history","description":"Requires the workspace `workspace:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Webhook ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Webhook not found"}}}}}}},"/workspaces/{wid}/webhooks/{id}/rotate":{"post":{"summary":"Rotate a webhook signing secret","description":"Requires the workspace `workspace:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. The replacement secret is returned once and signingVersion is set to 2.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Webhook ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"secret":{"type":"string","writeOnly":true},"signingVersion":{"type":"integer","const":2}},"required":["secret","signingVersion"]},"example":{"secret":"[REDACTED]","signingVersion":2}}}},"404":{"description":"Webhook not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Webhook not found"}}}}}}},"/workspaces/{wid}/automations":{"get":{"summary":"List linear and graph automations","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Linear automations include ordered steps; published graph automations expose graph=true instead of a flattened step list.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Automation"}}}}}}},"post":{"summary":"Create a legacy linear automation","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Maximum 50 per workspace. Supply exactly one legacy action or an ordered 1-20 step list; references may use only prior `{{steps.N.output}}` values. The resulting linear version is also available as a graph through the version and draft routes.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationInput"},"example":{"name":"Record and notify","event":"item.created","steps":[{"type":"log","config":{"message":"Task event received"}},{"type":"http","config":{"url":"https://hooks.example.test/tasks","method":"POST","headers":{"x-source":"hopya"},"body":"{{event}}"}}],"enabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Automation"}}}},"400":{"description":"Invalid automation or step sequence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid automation or step sequence"}}}}}}},"/workspaces/{wid}/automations/{id}":{"patch":{"summary":"Update automation metadata or legacy steps","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Replacing action/steps or changing the event on a linear automation creates a new immutable linear version. Published graphs reject legacy action, steps, and event changes with 409; change their trigger through a graph draft. Name and enabled remain patchable.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationPatch"},"example":{"steps":[{"type":"log","config":{"message":"Automation revision two"}}],"enabled":true}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Automation"}}}},"400":{"description":"Invalid automation or step sequence","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid automation or step sequence"}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}},"409":{"description":"Published graph cannot be changed through the legacy API","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Published graph cannot be changed through the legacy API"}}}}}},"delete":{"summary":"Delete an automation and its run history","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}}}}},"/workspaces/{wid}/automations/catalog":{"get":{"summary":"Read graph node and event descriptors","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Returns server-owned graph limits plus typed node manifests used by editors and data pickers.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationCatalog"}}}}}}},"/workspaces/{wid}/automations/{id}/draft":{"get":{"summary":"Read the current graph draft","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. If no draft exists, returns revision 0 with the current published version graph and updatedAt null.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationDraft"}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}}}},"put":{"summary":"Save a graph draft with optimistic concurrency","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Draft changes do not affect queued, active, or published versions. expectedRevision must match the current draft revision. Structural validation is reported in the response but invalid drafts may still be saved.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expectedRevision":{"type":"integer","minimum":0},"graph":{"$ref":"#/components/schemas/AutomationGraph"}},"required":["expectedRevision","graph"],"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationDraftSaved"}}}},"400":{"description":"Invalid graph shape","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid graph shape"}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}},"409":{"description":"Draft changed; reload before saving","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Draft changed; reload before saving"}}}}}}},"/workspaces/{wid}/automations/{id}/validate":{"post":{"summary":"Validate a supplied or saved draft graph","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Omit graph to validate the saved draft. Includes graph structure, control flow, upstream references, destination safety, and active workspace credential bindings.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"graph":{"$ref":"#/components/schemas/AutomationGraph"}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphValidation"}}}},"400":{"description":"No valid graph was supplied or saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"No valid graph was supplied or saved"}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}}}}},"/workspaces/{wid}/automations/{id}/publish":{"post":{"summary":"Publish the current graph draft","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Validates the exact draft revision and active credential bindings, creates an immutable graph version, changes the trigger event to the graph trigger, and retains the draft while atomically advancing its revision by one. Revisions remain monotonic across save/publish cycles; stale requests return 409. Returns the published version, not the draft; re-read the draft for its current revision. Queued and active runs are unchanged.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"expectedRevision":{"type":"integer","minimum":1}},"required":["expectedRevision"],"additionalProperties":false},"example":{"expectedRevision":1}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationVersion"}}}},"400":{"description":"Graph or credential binding is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Graph or credential binding is invalid"}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}},"409":{"description":"Draft changed; reload before publishing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Draft changed; reload before publishing"}}}}}}},"/workspaces/{wid}/automations/{id}/versions":{"get":{"summary":"List immutable published versions","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AutomationVersionSummary"}}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}}}}},"/workspaces/{wid}/automations/{id}/versions/{version}":{"get":{"summary":"Read one immutable published graph representation","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Both graph and legacy linear versions are represented as nodes and edges; format identifies their source form.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}},{"name":"version","in":"path","required":true,"description":"Positive immutable automation version.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationVersion"}}}},"404":{"description":"Automation version not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation version not found"}}}}}}},"/workspaces/{wid}/automations/{id}/preview":{"post":{"summary":"Preview graph control flow without side effects","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Uses the supplied graph or current published graph, an optional event, and optional node mock outputs. Actions are simulated with typed outputs; routing stops with an uncertainty marker when a control node depends on an unknown output. Every returned path entry has effect=none.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"graph":{"$ref":"#/components/schemas/AutomationGraph"},"event":{"type":"object","properties":{},"additionalProperties":true,"default":{}},"mockOutputs":{"type":"object","properties":{},"propertyNames":{"type":"string","minLength":1,"maxLength":100,"pattern":"^[A-Za-z0-9_-]+$"},"additionalProperties":true,"default":{}}},"additionalProperties":false}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GraphPreview"}}}},"400":{"description":"Invalid graph or preview event","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid graph or preview event"}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}}}}},"/workspaces/{wid}/automations/{id}/test":{"post":{"summary":"Queue a test run of the current automation version","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. The test is asynchronous and may perform real configured effects. Its synthetic event contains no task target, so a published graph containing any update_item node is rejected with 400 before enqueueing, even on an unselected branch. Use a real task event for those graphs. Monitor accepted runId through the run endpoint.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Automation ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","const":true},"event":{"type":"string","enum":["item.created","item.updated","item.deleted","node.created","node.updated","node.deleted","field.changed"]},"runId":{"type":"string","format":"uuid"},"status":{"type":"string","const":"pending"}},"required":["ok","event","runId","status"]},"example":{"ok":true,"event":"item.created","runId":"66666666-6666-4666-8666-666666666666","status":"pending"}}}},"400":{"description":"Test runs have no triggering task; use a real task event for Update task graphs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Test runs have no triggering task; use a real task event for Update task graphs"}}}},"404":{"description":"Automation not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation not found"}}}}}}},"/workspaces/{wid}/automations/runs":{"get":{"summary":"Monitor recent automation and webhook runs","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Returns at most 100 sanitized records. Linear step runs and graph node runs are separate arrays; raw queued event payloads, credentials, and secrets are omitted.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":20}},{"name":"automationId","in":"query","required":false,"description":"Automation ID; webhook runs are not selected by this filter.","schema":{"type":"string","format":"uuid"}},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","running","delivered","failed"]}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AutomationRun"}}}}},"400":{"description":"Invalid run filter","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid run filter"}}}}}}},"/workspaces/{wid}/automations/runs/{runId}":{"get":{"summary":"Read one automation or webhook run","description":"Requires both workspace `automations:manage` and `items:read` permissions. Workspace and resource identifiers are revalidated against the authenticated user. Step and node outputs/logs are bounded and sanitized; the raw event payload is omitted.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"runId","in":"path","required":true,"description":"Run ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationRun"}}}},"404":{"description":"Automation run not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation run not found"}}}}}}},"/workspaces/{wid}/automations/credentials":{"get":{"summary":"List automation credential metadata","description":"Requires automations:manage or credentials:manage. Secret values and encrypted material are never returned.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/AutomationCredential"}}}}}}},"post":{"summary":"Create a bound automation credential","description":"Requires the workspace `credentials:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. Stores a new encrypted credential version. origin contains only scheme, host, and optional port; pathPrefix optionally narrows where it may be sent. Public credential destinations require HTTPS unless explicitly allowed by the operator.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationCredentialCreate"},"example":{"name":"Service bearer","type":"bearer","origin":"https://api.example.test","pathPrefix":"/v1/tasks","secret":{"token":"[REDACTED]"}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationCredential"}}}},"400":{"description":"Credential or destination binding is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Credential or destination binding is invalid"}}}},"503":{"description":"Automation credential keyring is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation credential keyring is unavailable"}}}}}}},"/workspaces/{wid}/automations/credentials/{id}":{"get":{"summary":"Read automation credential metadata","description":"Requires automations:manage or credentials:manage. Secret values and encrypted material are never returned.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Credential ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationCredential"}}}},"404":{"description":"Credential not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Credential not found"}}}}}},"put":{"summary":"Replace an active credential secret","description":"Requires the workspace `credentials:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. expectedVersion provides optimistic concurrency. Type, origin, and pathPrefix are immutable; the optional name and type-specific secret are replaced in a new encrypted version.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Credential ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationCredentialReplace"},"example":{"expectedVersion":1,"name":"Service bearer","secret":{"token":"[REDACTED]"}}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AutomationCredential"}}}},"400":{"description":"Credential secret is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Credential secret is invalid"}}}},"404":{"description":"Active credential not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Active credential not found"}}}},"409":{"description":"Credential changed; reload before replacing","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Credential changed; reload before replacing"}}}},"503":{"description":"Automation credential keyring is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation credential keyring is unavailable"}}}}}},"delete":{"summary":"Revoke an automation credential","description":"Requires the workspace `credentials:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. Marks the credential revoked; metadata remains available and future execution cannot use it.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Credential ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"},"example":{"success":true}}}},"404":{"description":"Credential not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Credential not found"}}}}}}},"/workspaces/{wid}/automations/credentials/{id}/oauth/start":{"post":{"summary":"Start OAuth 2.0 authorization-code connection","description":"Requires the workspace `credentials:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. Requires an active oauth2 credential. Creates a single-user, ten-minute PKCE flow and returns the provider authorization URL.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"OAuth credential ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"authorizationUrl":{"type":"string","format":"uri"},"expiresAt":{"type":"string","format":"date-time"}},"required":["authorizationUrl","expiresAt"],"additionalProperties":false}}}},"400":{"description":"Credential is not OAuth 2.0 or its destination is invalid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Credential is not OAuth 2.0 or its destination is invalid"}}}},"404":{"description":"Credential not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Credential not found"}}}},"503":{"description":"Automation credential keyring is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation credential keyring is unavailable"}}}}}}},"/workspaces/{wid}/automations/credentials/{id}/oauth/callback":{"get":{"summary":"Complete OAuth 2.0 authorization-code connection","description":"Requires the workspace `credentials:manage` permission. Workspace and resource identifiers are revalidated against the authenticated user. Consumes the authenticated user's one-time PKCE state, exchanges the code without redirects, and stores tokens only in a new encrypted credential version.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"OAuth credential ID in this workspace.","schema":{"type":"string","format":"uuid"}},{"name":"state","in":"query","required":true,"schema":{"type":"string","minLength":20,"maxLength":200,"writeOnly":true}},{"name":"code","in":"query","required":true,"schema":{"type":"string","minLength":1,"maxLength":4000,"writeOnly":true}}],"responses":{"302":{"description":"Redirect to /integrations?oauth=connected"},"400":{"description":"OAuth state is invalid, expired, or malformed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"OAuth state is invalid, expired, or malformed"}}}},"409":{"description":"OAuth credential changed; start the connection again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"OAuth credential changed; start the connection again"}}}},"502":{"description":"OAuth token exchange failed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"OAuth token exchange failed"}}}},"503":{"description":"Automation credential keyring is unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Automation credential keyring is unavailable"}}}}}}},"/workspaces/{wid}/agent":{"post":{"summary":"Ask the optional AI assistant","description":"Requires both agent:use and items:read. Context is bounded to 100 recent tasks and 100 lists. The response can only propose a task; mutations require separate explicit human confirmation through task routes.","tags":["Automations"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","minLength":1,"maxLength":8000}},"required":["message"],"additionalProperties":false},"example":{"message":"Summarize current release work and suggest one next task."}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"reply":{"type":"string","minLength":1,"maxLength":16000},"proposal":{"anyOf":[{"type":"object","properties":{"title":{"type":"string","maxLength":300},"description":{"type":"string","maxLength":10000},"nodeId":{"type":"string","format":"uuid"},"dueDate":{"anyOf":[{"type":"string","format":"date","pattern":"^\\d{4}-\\d{2}-\\d{2}$"},{"type":"null"}]},"priority":{"type":"string","enum":["none","low","medium","high","urgent"]}},"required":["title"],"additionalProperties":false},{"type":"null"}]}},"required":["reply"]}}}},"429":{"description":"Assistant is busy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Assistant is busy"}}}},"502":{"description":"AI provider failed; no tasks were changed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"AI provider failed; no tasks were changed"}}}},"503":{"description":"AI assistant is disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"AI assistant is disabled"}}}}}}},"/workspaces/{wid}/items/{id}/attachments":{"get":{"summary":"List task attachments","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Attachment"}}}}}}},"post":{"summary":"Upload a task attachment","description":"Requires the workspace `items:write` permission. Workspace and resource identifiers are revalidated against the authenticated user. Base64-decoded content is limited to 10 MiB; filenames and storage object keys are validated independently.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":255},"contentType":{"type":"string","maxLength":127},"data":{"type":"string","format":"byte","writeOnly":true}},"required":["name","contentType","data"],"additionalProperties":false},"example":{"name":"release-notes.txt","contentType":"text/plain","data":"[BASE64 FILE DATA]"}}}},"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Attachment"}}}},"400":{"description":"Invalid attachment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Invalid attachment"}}}},"413":{"description":"Attachment exceeds 10 MiB","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Attachment exceeds 10 MiB"}}}},"503":{"description":"Attachment storage unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Attachment storage unavailable"}}}}}}},"/workspaces/{wid}/items/{id}/attachments/{attachmentId}":{"get":{"summary":"Download an attachment","description":"Requires the workspace `items:read` permission. Workspace and resource identifiers are revalidated against the authenticated user.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}},{"name":"attachmentId","in":"path","required":true,"description":"Attachment ID on this task.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Attachment bytes with forced download disposition"},"404":{"description":"Attachment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Attachment not found"}}}},"503":{"description":"Attachment storage unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Attachment storage unavailable"}}}}}},"delete":{"summary":"Delete an attachment","description":"Requires the workspace `items:delete` permission. Workspace and resource identifiers are revalidated against the authenticated user. Access is revoked before best-effort physical cleanup.","tags":["Tasks"],"parameters":[{"name":"wid","in":"path","required":true,"description":"Workspace ID; membership and the operation permission are checked server-side.","schema":{"type":"string","format":"uuid"}},{"name":"id","in":"path","required":true,"description":"Task ID in this workspace.","schema":{"type":"string","format":"uuid"}},{"name":"attachmentId","in":"path","required":true,"description":"Attachment ID on this task.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"cleanupPending":{"type":"boolean"}},"required":["success","cleanupPending"]},"example":{"success":true,"cleanupPending":false}}}},"404":{"description":"Attachment not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":"Attachment not found"}}}}}}}},"x-hopya-permissions":["items:read","items:write","items:delete","documents:read","documents:write","documents:delete","comments:create","comments:manage","structure:write","members:manage","roles:manage","workspace:manage","automations:manage","credentials:manage","agent:use"]}