{"openapi":"3.1.0","info":{"title":"Tre REST API","version":"0.2.0","description":"Complete REST contract for Tre — the same service layer the MCP surface calls, over plain HTTP.\n**Audience.** A workspace-bound token sees only that workspace in identity workspace lists, boards, users, timeline, activity and export. Omitted workspace defaults to its audience for creates. Outside workspace names and cardKeys answer the same NOT_FOUND as unknown ones; direct board UUID access retains the exact non-member FORBIDDEN response. Token listing, revocation and exported token metadata exclude unbound and differently bound tokens. Bound tokens cannot create workspaces (403 FORBIDDEN: Workspace-bound tokens cannot create workspaces), before writes or cache replay. Sessions and unbound tokens keep their existing access.\nReplay results and in-flight locks are partitioned by non-null token audience on REST and MCP. Same-audience retries replay normally; sessions and unbound tokens retain the existing shared namespace.\n\n**Authentication.** Send a `tre_pat_*` personal API token as a Bearer credential (create one in Tre: avatar menu → API tokens). A token acts as its creator with a scope ceiling: `read` allows reads, `write` also allows ordinary mutations, and `admin` also allows workspace administration and token management. The creator's workspace and board roles still apply; scope never grants a role. Existing personal tokens default to `admin`. Scope denials answer 403 FORBIDDEN naming the held scope and operation. Browser sessions have no token ceiling. Account deletion requires the web session even for admin tokens. The workspace guidance card is written by a workspace owner or admin from the web app; a Bearer token writes it only under a guidance write grant that owner or admin made on it (grantGuidanceWrite, web session only) and only with `confirm: 'guidance'` plus `expectedUpdatedAt` on updateCard — no scope implies it. A revoked token answers 401.\n\n**Errors.** Every failure returns `{ \"error\": { \"code\", \"message\", \"details\"? } }`. Codes: `BAD_REQUEST`, `VALIDATION_ERROR`, `UNAUTHENTICATED`, `FORBIDDEN`, `NOT_FOUND`, `CONFLICT`, `STALE_CURSOR`, `PRECONDITION_FAILED`, `IDEMPOTENCY_KEY_REUSED`, `RATE_LIMITED`, `SERVICE_UNAVAILABLE`, `INTERNAL`. Unexpected server faults are reported only as `INTERNAL`; details are never leaked.\n\n**Rate limits.** Per authenticated user, per bucket: reads share one budget of 600/min, except the timeline (120/min) and the account export (5 per hour). Writes are split per resource at 60/min each: boards (members and background included), lists, cards (comments and subtasks included), card moves, checklist. Workspace administration — membership, invitations, ownership, rename, deletion — is limited to 20/min, token and guidance-grant writes to 10/min, account writes to 5/min and workspace creation to 3/min; the public and OAuth endpoints, the internal document save and the realtime token have buckets of their own. A 429 carries `details.retryAfterSeconds`.\n\n**Retrying a write safely.** The ten creation endpoints accept an `Idempotency-Key` header: the same key from the same caller on the same route replays the first response for 24 hours instead of creating a second row. The same key with a matching body fingerprint replays; a reused key with a different body answers 422 `IDEMPOTENCY_KEY_REUSED`. Derive the key from the payload, and never reuse a generic value. Updates, moves, reorders and deletes converge when repeated and need no key.\n\n**Not overwriting a concurrent writer.** `PATCH /api/cards/{cardId}` accepts `expectedUpdatedAt`: pass back the `updatedAt` you read, verbatim, and a card that changed in between answers 412 `PRECONDITION_FAILED` rather than being silently overwritten. It is compared as an exact string, so never re-format or re-parse it. It guards the card row alone: comments, checklist items, subtasks and moves never bump `updatedAt`. Or pass `expectedSeq` (the card's `seq` from getCard, exclusive with `expectedUpdatedAt`) to cover comment, checklist-item and subtask writes and moves across lists too — not reorders, a move within one list, or an editor autosave inside its checkpoint window, which append no event. A 412 carries `details.currentSeq` and `details.events` (the missed events, oldest first, at most 20).\n\n**Addressing a card.** Every card-scoped path accepts either the card's UUID or its stable `cardKey` (for example `DESIGN-42`) — the address worth keeping between sessions, since UUIDs should not be cached. The internal Yjs state endpoints stay UUID-only.\n\n**Reading cheaply.** `GET /api/boards/{boardId}/cards?view=summary` returns the `CardSummary` projection — its thirteen always-present fields plus `match` under `textContains` — instead of whole cards — narrow with `titleContains`, then fetch the one card you want. `GET /api/catch-up` answers \"what changed since I was last here\": call it without a cursor for a brief of what you can read, then keep the cursor it returns and pass it back next time for the delta. Treat that cursor as opaque: store it verbatim, never parse it.\n\n**Relationship to MCP.** Tre also exposes a curated Model Context Protocol surface at `/api/mcp`, covering the core board/list/card/checklist workflow and workspace membership. It is not an alias for every endpoint here; this document is the complete contract.\n\n**On this installation.** Billing sessions are limited with workspace administration (20/min); operator console writes are limited to 10/min, the cap on what one operator session can do in a minute; the Stripe webhook has no bucket: its signature check guards it instead. The operator agent's proposal endpoint accepts an `Idempotency-Key` like the ten creation endpoints."},"servers":[{"url":"https://tre-app.com"}],"security":[{"bearerAuth":[]}],"tags":[{"name":"Boards"},{"name":"Lists"},{"name":"Cards"},{"name":"Checklist"},{"name":"Subtasks"},{"name":"Comments"},{"name":"History"},{"name":"Timeline"},{"name":"Events"},{"name":"Users"},{"name":"Tokens"},{"name":"Workspaces"},{"name":"Public"},{"name":"OAuth"},{"name":"Operator"},{"name":"Operator agent"},{"name":"Internal"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"tre_pat_*"},"secureSessionAuth":{"type":"apiKey","in":"cookie","name":"__Secure-authjs.session-token","description":"Authenticated web session on HTTPS. UI session-only; not a Bearer token."},"sessionAuth":{"type":"apiKey","in":"cookie","name":"authjs.session-token","description":"Authenticated web session on HTTP (local development). UI session-only; not a Bearer token."}},"headers":{"TreEventSeq":{"name":"Tre-Event-Seq","description":"Workspace event sequence of the ledger row this mutation appended. Same number MCP returns under `_meta[\"io.tre-app/event\"].seq`. Absent on reads and on writes that do not append.","schema":{"type":"string","pattern":"^[0-9]+$"}}},"responses":{"BadRequest":{"description":"Invalid request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Unauthenticated":{"description":"Unauthenticated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Forbidden":{"description":"Forbidden: insufficient role or token scope; scope denials name the held scope and the operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"NotFound":{"description":"Not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"Conflict":{"description":"Conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"IdempotencyKeyReused":{"description":"Idempotency-Key reused with a different request body (IDEMPOTENCY_KEY_REUSED)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"RateLimited":{"description":"Rate limited","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"InternalError":{"description":"Internal server error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"ServiceUnavailable":{"description":"Temporarily unavailable","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}}},"schemas":{"ErrorResponse":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"},"details":{}},"required":["code","message"],"additionalProperties":false}},"required":["error"],"additionalProperties":false},"Board":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"slug":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"keyPrefix":{"type":"string"},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"archivedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"backgroundKind":{"anyOf":[{"type":"string","enum":["color","gradient","image"]},{"type":"null"}]},"backgroundValue":{"anyOf":[{"type":"string"},{"type":"null"}]},"isPrivate":{"type":"boolean"}},"required":["id","slug","name","title","keyPrefix","order","createdAt","archivedAt","backgroundKind","backgroundValue","isPrivate"],"additionalProperties":false},"BoardWithRole":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"slug":{"type":"string"},"name":{"type":"string"},"title":{"type":"string"},"keyPrefix":{"type":"string"},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"archivedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"backgroundKind":{"anyOf":[{"type":"string","enum":["color","gradient","image"]},{"type":"null"}]},"backgroundValue":{"anyOf":[{"type":"string"},{"type":"null"}]},"isPrivate":{"type":"boolean"},"role":{"type":"string","enum":["editor","viewer"]}},"required":["id","slug","name","title","keyPrefix","order","createdAt","archivedAt","backgroundKind","backgroundValue","isPrivate","role"],"additionalProperties":false},"BoardsResponse":{"type":"object","required":["boards"],"properties":{"boards":{"type":"array","items":{"$ref":"#/components/schemas/Board"}}}},"BoardCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"keyPrefix":{"type":"string","pattern":"^[A-Z0-9]{2,8}$"},"isPrivate":{"default":false,"type":"boolean"},"workspace":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z0-9-]+$"}},"required":["name"]},"BoardUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"isPrivate":{"type":"boolean"}}},"BoardReorder":{"type":"object","properties":{"boardIds":{"minItems":1,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}}},"required":["boardIds"]},"BoardBackgroundPreset":{"oneOf":[{"type":"object","properties":{"kind":{"type":"string","const":"color"},"value":{"type":"string","enum":["#f4ebd6","#e8f0e1","#e4ecf7","#f2e8f0","#fce8dc","#fef3c7","#e0f2f1","#f5d9e1","#dde7f2","#e7e4f7","#ece9e2","#fbe4e4"]}},"required":["kind","value"]},{"type":"object","properties":{"kind":{"type":"string","const":"gradient"},"value":{"type":"string","enum":["linear-gradient(135deg, #e4ecf7 0%, #f2e8f0 100%)","linear-gradient(135deg, #fce8dc 0%, #f5d9e1 100%)","linear-gradient(135deg, #dff1ec 0%, #e4ecf7 100%)","linear-gradient(135deg, #fbf3e0 0%, #f0e4d3 100%)","linear-gradient(135deg, #fef3c7 0%, #fce8dc 100%)","linear-gradient(135deg, #e7e4f7 0%, #dde7f2 100%)","linear-gradient(135deg, #e8f0e1 0%, #fef3c7 100%)","linear-gradient(135deg, #f5d9e1 0%, #e7e4f7 100%)"]}},"required":["kind","value"]}]},"BoardMemberCreate":{"type":"object","properties":{"email":{"format":"email","type":"string"},"role":{"type":"string","enum":["editor","viewer"]}},"required":["email","role"]},"BoardMemberUpdate":{"type":"object","properties":{"role":{"type":"string","enum":["editor","viewer"]}},"required":["role"]},"BoardMember":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"email":{"type":"string","format":"email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","enum":["editor","viewer"]},"createdAt":{"description":"When the membership began. The list carries it; the add answer does not.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["userId","email","name","role"],"additionalProperties":false},"BoardMembersResponse":{"type":"object","required":["members"],"properties":{"members":{"type":"array","items":{"$ref":"#/components/schemas/BoardMember"}}}},"List":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"boardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"title":{"type":"string"},"color":{"type":"string"},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["id","boardId","title","color","order"],"additionalProperties":false},"ListsResponse":{"type":"object","required":["lists"],"properties":{"lists":{"type":"array","items":{"$ref":"#/components/schemas/List"}}}},"ListCreate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":100},"color":{"type":"string","maxLength":40}},"required":["title"]},"ListUpdate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":100},"color":{"type":"string","maxLength":40}}},"ListReorder":{"type":"object","properties":{"listIds":{"minItems":1,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}}},"required":["listIds"]},"Card":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"boardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"listId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cardKey":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"verifiedOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Day the named source was actually checked, never later than the server UTC day. Independent of updatedAt and the status date in the description; never advance for editorial work."},"verificationSource":{"anyOf":[{"type":"string","minLength":1,"maxLength":400},{"type":"null"}],"description":"Source reference and scope of the last factual verification (document, record, URL or cardKey). Set or clear together with verifiedOn."},"links":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["label","url"],"additionalProperties":false}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"createdByUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"assigneeUserIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"kind":{"anyOf":[{"type":"string","enum":["control","work","reference","decision","digest","guidance"]},{"type":"null"}]}},"required":["id","boardId","listId","cardNumber","cardKey","title","description","color","order","startDate","endDate","scheduleState","actualStartDate","actualEndDate","verifiedOn","verificationSource","links","createdAt","updatedAt","createdByUserId","assigneeUserIds","kind"],"additionalProperties":false},"CardUpdated":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"boardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"listId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cardKey":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"verifiedOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Day the named source was actually checked, never later than the server UTC day. Independent of updatedAt and the status date in the description; never advance for editorial work."},"verificationSource":{"anyOf":[{"type":"string","minLength":1,"maxLength":400},{"type":"null"}],"description":"Source reference and scope of the last factual verification (document, record, URL or cardKey). Set or clear together with verifiedOn."},"links":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["label","url"],"additionalProperties":false}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"createdByUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"assigneeUserIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"kind":{"anyOf":[{"type":"string","enum":["control","work","reference","decision","digest","guidance"]},{"type":"null"}]},"merged":{"description":"Present when a stale expectedUpdatedAt was reconciled per block (S-D5): the blocks others changed in between.","type":"object","properties":{"sections":{"type":"array","items":{"type":"string","enum":["purpose","status","next","other"]}}},"required":["sections"],"additionalProperties":false}},"required":["id","boardId","listId","cardNumber","cardKey","title","description","color","order","startDate","endDate","scheduleState","actualStartDate","actualEndDate","verifiedOn","verificationSource","links","createdAt","updatedAt","createdByUserId","assigneeUserIds","kind"],"additionalProperties":false},"TrashedCard":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"boardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"listId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"cardNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cardKey":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"verifiedOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Day the named source was actually checked, never later than the server UTC day. Independent of updatedAt and the status date in the description; never advance for editorial work."},"verificationSource":{"anyOf":[{"type":"string","minLength":1,"maxLength":400},{"type":"null"}],"description":"Source reference and scope of the last factual verification (document, record, URL or cardKey). Set or clear together with verifiedOn."},"links":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["label","url"],"additionalProperties":false}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"createdByUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"assigneeUserIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"kind":{"anyOf":[{"type":"string","enum":["control","work","reference","decision","digest","guidance"]},{"type":"null"}]},"deletedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","boardId","listId","cardNumber","cardKey","title","description","color","order","startDate","endDate","scheduleState","actualStartDate","actualEndDate","verifiedOn","verificationSource","links","createdAt","updatedAt","createdByUserId","assigneeUserIds","kind","deletedAt"],"additionalProperties":false},"CardDetail":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"boardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"listId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardNumber":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"cardKey":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"verifiedOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Day the named source was actually checked, never later than the server UTC day. Independent of updatedAt and the status date in the description; never advance for editorial work."},"verificationSource":{"anyOf":[{"type":"string","minLength":1,"maxLength":400},{"type":"null"}],"description":"Source reference and scope of the last factual verification (document, record, URL or cardKey). Set or clear together with verifiedOn."},"links":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["label","url"],"additionalProperties":false}},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"createdByUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"assigneeUserIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"kind":{"anyOf":[{"type":"string","enum":["control","work","reference","decision","digest","guidance"]},{"type":"null"}]},"seq":{"type":"integer","minimum":0,"maximum":9007199254740991},"cites":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"card":{"type":"string"},"title":{"type":"string"}},"required":["card","title"],"additionalProperties":false}},"citedBy":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"card":{"type":"string"},"title":{"type":"string"}},"required":["card","title"],"additionalProperties":false}},"citedByDigests":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"The number of digest cards (kind: digest) citing this card on boards you can read, including those beyond the 50-row cap of citedBy, which lists digests last."},"subtasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"title":{"type":"string"},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"color":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","cardId","title","startDate","endDate","scheduleState","actualStartDate","actualEndDate","order","color","createdAt"],"additionalProperties":false}}},"required":["id","boardId","listId","cardNumber","cardKey","title","description","color","order","startDate","endDate","scheduleState","actualStartDate","actualEndDate","verifiedOn","verificationSource","links","createdAt","updatedAt","createdByUserId","assigneeUserIds","kind","seq","cites","citedBy","citedByDigests","subtasks"],"additionalProperties":false},"CardsResponse":{"type":"object","required":["cards"],"properties":{"cards":{"type":"array","items":{"$ref":"#/components/schemas/Card"}}}},"TrashedCardsResponse":{"type":"object","required":["cards"],"properties":{"cards":{"type":"array","items":{"$ref":"#/components/schemas/TrashedCard"}}}},"CardSummary":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardKey":{"type":"string"},"title":{"type":"string"},"listId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"verifiedOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Day the named source was actually checked, never later than the server UTC day. Independent of updatedAt and the status date in the description; never advance for editorial work."},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"statusDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"stale":{"type":"boolean"},"match":{"type":"object","properties":{"field":{"type":"string","enum":["title","description","comment","checklist","subtask"]},"snippet":{"type":"string","maxLength":120}},"required":["field","snippet"],"additionalProperties":false}},"required":["id","cardKey","title","listId","startDate","endDate","scheduleState","actualStartDate","actualEndDate","verifiedOn","updatedAt","statusDate","stale"],"additionalProperties":false},"CardSummariesResponse":{"type":"object","required":["cards"],"properties":{"cards":{"type":"array","items":{"$ref":"#/components/schemas/CardSummary"}}}},"CardLint":{"type":"object","properties":{"cardKey":{"type":"string"},"title":{"type":"string"},"findings":{"minItems":1,"type":"array","items":{"type":"string","enum":["orphan","unresolved_reference","stale_status","missing_status","oversize_description","duplicate_status","overdue","stale_verification","status_log"]},"description":"Findings from the closed set — advice, never a write refusal. `orphan` means no citation in or out on boards the caller can read; `unresolved_reference` means no card the caller can read resolves a named key — a card on a private board the caller is not a member of reads as absent for both; `missing_status` means neither a STATUS/STATO nor an UPDATED/AGGIORNATO line, on an open card whose kind is not reference, digest, guidance or control. `duplicate_status` names a card with more than one STATUS/STATO section — the most recent date is the one read. `overdue` (since 2026-09-26) means the card itself, or one of its subtasks, has a planned end strictly before today (the server UTC date) with no observed end (`actualEndDate`); `stale_verification` means the card was verified (`verifiedOn`) before the dated STATUS/UPDATED line of a card its description cites — re-read the source or accept the drift in a dated comment. `status_log` (since 2026-10-15) means the STATUS/STATO block reads as a chronology — two or more clock times, or three or more dates inside its text: keep STATUS to where things stand and put the chronology in one dated comment. A closed card — `actualEndDate` set, or `scheduleState: cancelled` — is never `stale_status`, `missing_status`, `overdue`, `stale_verification` or `status_log`."}},"required":["cardKey","title","findings"],"additionalProperties":false},"CardLintsResponse":{"type":"object","required":["cards"],"properties":{"cards":{"type":"array","items":{"$ref":"#/components/schemas/CardLint"}}}},"WorkspaceCardSearchResponse":{"type":"object","properties":{"cards":{"maxItems":50,"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardKey":{"type":"string"},"title":{"type":"string"},"listId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"verifiedOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Day the named source was actually checked, never later than the server UTC day. Independent of updatedAt and the status date in the description; never advance for editorial work."},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"statusDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"stale":{"type":"boolean"},"match":{"type":"object","properties":{"field":{"type":"string","enum":["title","description","comment","checklist","subtask"]},"snippet":{"type":"string","maxLength":120}},"required":["field","snippet"],"additionalProperties":false},"boardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"board":{"type":"string","minLength":1}},"required":["id","cardKey","title","listId","startDate","endDate","scheduleState","actualStartDate","actualEndDate","verifiedOn","updatedAt","statusDate","stale","boardId","board"],"additionalProperties":false}},"truncated":{"type":"boolean","description":"True when more than 50 cards matched and only the 50 best ranked are listed (by the field holding every word — title, ALIASES line, description, comment, checklist, subtask, then words spread over fields — most recently updated first within a rank); false means every match on the boards you can read is here."}},"required":["cards","truncated"],"additionalProperties":false},"BoardCardsResponse":{"anyOf":[{"$ref":"#/components/schemas/CardsResponse"},{"$ref":"#/components/schemas/CardSummariesResponse"},{"$ref":"#/components/schemas/CardLintsResponse"},{"$ref":"#/components/schemas/TrashedCardsResponse"}]},"CardCreate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"listId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"description":{"description":"Concise narrative context carrying only the current truth, written under fixed uppercase labels: `PURPOSE: …`, a dated `STATUS YYYY-MM-DD: …` line rewritten in place (preserve its date during editorial corrections), `NEXT STEP: action → who` (who acts: the name of a person, the name of a token, or `waiting for <name> (<organisation>)`; a date only when real) — or the Italian set SCOPO / STATO / PROSSIMO PASSO. The server reads that dated line for freshness and staleness; the colon is the canonical delimiter, a dash is accepted and normalized to it. A line break is stored as `\\n`: `\\r\\n` or a lone `\\r` is accepted and normalized to it, so the text you read back can differ from the text you sent by those characters. History belongs in dated card comments, never in layered corrections here. Do not place a mutable list of independently trackable records or steps here; use checklist items.","type":"string","maxLength":2000},"color":{"type":"string","maxLength":40},"startDate":{"description":"Start of the retained plan (not an observed start). For one exact operational deadline, pass the same ISO day in startDate and endDate. Never infer it from a reference date.","anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"description":"End of the retained plan (not an observed completion). For one exact operational deadline, pass the same ISO day in startDate and endDate.","anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"description":"Meaning of the retained schedule; one server rule on every surface. Omit it: a create with a planned date is stored as planned, one without as unclassified; on update, touching a planned date promotes unclassified to planned, clearing both planned dates resets to unclassified, any other stored state is kept. Send suspended or cancelled explicitly; a non-unclassified state with both planned dates null is refused (400 BAD_REQUEST).","type":"string","enum":["unclassified","planned","suspended","cancelled"]},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"verifiedOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Day the named source was actually checked, never later than the server UTC day. Independent of updatedAt and the status date in the description; never advance for editorial work."},"verificationSource":{"anyOf":[{"type":"string","minLength":1,"maxLength":400},{"type":"null"}],"description":"Source reference and scope of the last factual verification (document, record, URL or cardKey). Set or clear together with verifiedOn."},"links":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["label","url"]}},"assigneeUserIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"kind":{"description":"What the card is for: control | work | reference | decision | digest | guidance. `guidance` cannot be set at creation by a token (403): create the card, then promote it with update_card under a guidance write grant (Settings → API tokens → Allow guidance writes) with confirm: 'guidance' and expectedUpdatedAt; a workspace owner or admin sets it from the web app directly.","type":"string","enum":["control","work","reference","decision","digest","guidance"]},"ifSimilar":{"description":"Duplicate guard over the titles on boards you can read in the workspace (trigram similarity >= 0.5, at most five): 'reject' answers 409 CONFLICT with details.similar and creates nothing; the default 'create' creates the card and returns those titles as similar in the response, so a near-duplicate is never silent.","type":"string","enum":["create","reject"]},"position":{"anyOf":[{"type":"string","const":"top"},{"type":"string","const":"bottom"},{"type":"object","properties":{"afterCardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"required":["afterCardId"]}],"description":"Where the new card lands: 'top', 'bottom' (the default), or { afterCardId } — the anchor is the card's UUID only, not a cardKey."},"checklist":{"description":"Initial checklist: one item per independently trackable source record, decision, execution step, or verification gate. Permanent control cards remain even when this array is empty.","maxItems":50,"type":"array","items":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":500,"description":"Text for one independently trackable source record, decision, execution step, or verification gate. Begin with a stable source identifier when one exists."},"assigneeUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"priority":{"type":"string","enum":["none","low","normal","high","urgent"]}},"required":["text"]}}},"required":["title","listId"]},"CardUpdate":{"type":"object","properties":{"expectedUpdatedAt":{"description":"The `updatedAt` you read before deciding this change, passed back VERBATIM — the comparison is exact string equality against the stored ISO serialization, not a timestamp comparison. When the card has changed since, the update is refused (412) instead of overwriting the other writer — re-read and decide again. It guards the card row alone: comments, checklist items, subtasks and moves never bump `updatedAt`. Exclusive with `expectedSeq`.","type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"expectedSeq":{"description":"The card's `seq` from get_card (or the receipt of your last write to this card: `seq` runs across the workspace, so the receipt of a write to another card would pass over this card's events). The write is refused with 412 when any retained event of the card has seq greater than this — comment, checklist-item and subtask writes, moves across lists and `update_card`/PATCH writes to the card row. What appends no event is not seen: a reorder, a move within one list, or an editor autosave inside its checkpoint window (pass `expectedUpdatedAt` when a human may be typing in the card). Exclusive with `expectedUpdatedAt`. A card with no retained events has seq 0; expectedSeq 0 then passes.","type":"integer","minimum":0,"maximum":9007199254740991},"title":{"type":"string","minLength":1,"maxLength":200},"description":{"description":"Concise narrative context carrying only the current truth, written under fixed uppercase labels: `PURPOSE: …`, a dated `STATUS YYYY-MM-DD: …` line rewritten in place (preserve its date during editorial corrections), `NEXT STEP: action → who` (who acts: the name of a person, the name of a token, or `waiting for <name> (<organisation>)`; a date only when real) — or the Italian set SCOPO / STATO / PROSSIMO PASSO. The server reads that dated line for freshness and staleness; the colon is the canonical delimiter, a dash is accepted and normalized to it. A line break is stored as `\\n`: `\\r\\n` or a lone `\\r` is accepted and normalized to it, so the text you read back can differ from the text you sent by those characters. History belongs in dated card comments, never in layered corrections here. Do not place a mutable list of independently trackable records or steps here; use checklist items.","type":"string","maxLength":2000},"sections":{"type":"object","properties":{"SCOPO":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"PURPOSE":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"STATO":{"anyOf":[{"type":"object","properties":{"date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"The day the described state applies, YYYY-MM-DD."},"text":{"type":"string","maxLength":2000}},"required":["date","text"]},{"type":"null"}]},"STATUS":{"anyOf":[{"type":"object","properties":{"date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"The day the described state applies, YYYY-MM-DD."},"text":{"type":"string","maxLength":2000}},"required":["date","text"]},{"type":"null"}]},"AGGIORNATO":{"anyOf":[{"type":"object","properties":{"date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"The day the described state applies, YYYY-MM-DD."},"text":{"type":"string","maxLength":2000}},"required":["date","text"]},{"type":"null"}]},"UPDATED":{"anyOf":[{"type":"object","properties":{"date":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$","description":"The day the described state applies, YYYY-MM-DD."},"text":{"type":"string","maxLength":2000}},"required":["date","text"]},{"type":"null"}]},"PROSSIMO_PASSO":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"PROSSIMO PASSO":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"NEXT_STEP":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"NEXT STEP":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"ALTRO":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]},"OTHER":{"anyOf":[{"type":"string","maxLength":2000},{"type":"null"}]}},"additionalProperties":false,"description":"Rewrite one or more blocks of the description and leave the rest exactly as they are: { PURPOSE, STATUS: { date, text }, NEXT_STEP, OTHER } or the Italian keys (SCOPO, STATO, PROSSIMO_PASSO, ALTRO). null clears a block. Exclusive with `description`. A block ends at the next line that opens with an uppercase `LABEL:`: a paragraph such as `SOURCES: …` belongs to OTHER and survives a write to the other three, so the text of PURPOSE, STATUS or NEXT STEP cannot carry such a line below its first (400, details.rule `block-text`); write OTHER, replaced whole, to change or remove it. A line break in the text of a block is stored as `\\n` (`\\r\\n` and a lone `\\r` are normalized to it). With a stale expectedUpdatedAt, a call that sends sections alone still applies when none of the named blocks changed in between (the response carries `merged.sections`, the blocks others changed); a named block that moved on answers 412 with details.conflictingSections. A stale call that also sends any other field, even one restated unchanged, is refused whole (412) and writes nothing."},"color":{"type":"string","maxLength":40},"startDate":{"description":"Start of the retained plan (not an observed start). For one exact operational deadline, pass the same ISO day in startDate and endDate. Never infer it from a reference date.","anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"description":"End of the retained plan (not an observed completion). For one exact operational deadline, pass the same ISO day in startDate and endDate.","anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"description":"Meaning of the retained schedule; one server rule on every surface. Omit it: a create with a planned date is stored as planned, one without as unclassified; on update, touching a planned date promotes unclassified to planned, clearing both planned dates resets to unclassified, any other stored state is kept. Send suspended or cancelled explicitly; a non-unclassified state with both planned dates null is refused (400 BAD_REQUEST).","type":"string","enum":["unclassified","planned","suspended","cancelled"]},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"verifiedOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Day the named source was actually checked, never later than the server UTC day. Independent of updatedAt and the status date in the description; never advance for editorial work."},"verificationSource":{"anyOf":[{"type":"string","minLength":1,"maxLength":400},{"type":"null"}],"description":"Source reference and scope of the last factual verification (document, record, URL or cardKey). Set or clear together with verifiedOn."},"links":{"maxItems":20,"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":200},"url":{"type":"string","minLength":1,"maxLength":2048}},"required":["label","url"]}},"assigneeUserIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"kind":{"description":"What the card is for; null clears it. Lint reads reference/digest/guidance. Setting `guidance`, changing the kind of the guidance card, or rewriting its description is for a workspace owner or admin from the web app — or for a token that owner or admin has allowed for it (Settings → API tokens → Allow guidance writes, time-limited and revocable), which must then also send confirm: 'guidance' and expectedUpdatedAt; any other caller answers 403.","anyOf":[{"type":"string","enum":["control","work","reference","decision","digest","guidance"]},{"type":"null"}]},"confirm":{"description":"Required, together with expectedUpdatedAt, when a token rewrites the guidance card's description, promotes a card to kind guidance or changes the guidance card's kind under a guidance write grant: pass exactly 'guidance'. Ignored on every other write.","type":"string","const":"guidance"}}},"CardMove":{"type":"object","properties":{"toListId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"toIndex":{"anyOf":[{"type":"integer","minimum":0,"maximum":9007199254740991},{"type":"null"}]}},"required":["toListId","toIndex"]},"ChecklistItem":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"text":{"type":"string"},"completed":{"type":"boolean"},"assigneeUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"priority":{"type":"string","enum":["none","low","normal","high","urgent"]}},"required":["id","cardId","text","completed","assigneeUserId","order","priority"],"additionalProperties":false},"ChecklistResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ChecklistItem"}}}},"ChecklistItemCreate":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":500,"description":"Text for one independently trackable source record, decision, execution step, or verification gate. Begin with a stable source identifier when one exists."},"assigneeUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"priority":{"type":"string","enum":["none","low","normal","high","urgent"]}},"required":["text"]},"ChecklistItemUpdate":{"type":"object","properties":{"text":{"type":"string","minLength":1,"maxLength":500,"description":"Text for one independently trackable source record, decision, execution step, or verification gate. Begin with a stable source identifier when one exists."},"completed":{"type":"boolean"},"assigneeUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"priority":{"type":"string","enum":["none","low","normal","high","urgent"]}}},"ChecklistReorder":{"type":"object","properties":{"itemIds":{"minItems":1,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}}},"required":["itemIds"]},"Subtask":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"title":{"type":"string"},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"color":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","cardId","title","startDate","endDate","scheduleState","actualStartDate","actualEndDate","order","color","createdAt"],"additionalProperties":false},"SubtaskItemsResponse":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Subtask"}}}},"SubtaskCreate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"description":"Meaning of the retained schedule; one server rule on every surface. Omit it: a create with a planned date is stored as planned, one without as unclassified; on update, touching a planned date promotes unclassified to planned, clearing both planned dates resets to unclassified, any other stored state is kept. Send suspended or cancelled explicitly; a non-unclassified state with both planned dates null is refused (400 BAD_REQUEST).","type":"string","enum":["unclassified","planned","suspended","cancelled"]},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"color":{"type":"string","maxLength":40}},"required":["title"]},"SubtaskUpdate":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":200},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"description":"Meaning of the retained schedule; one server rule on every surface. Omit it: a create with a planned date is stored as planned, one without as unclassified; on update, touching a planned date promotes unclassified to planned, clearing both planned dates resets to unclassified, any other stored state is kept. Send suspended or cancelled explicitly; a non-unclassified state with both planned dates null is refused (400 BAD_REQUEST).","type":"string","enum":["unclassified","planned","suspended","cancelled"]},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"color":{"type":"string","maxLength":40}}},"SubtaskReorder":{"type":"object","properties":{"subtaskIds":{"minItems":1,"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}}},"required":["subtaskIds"]},"CommentCreate":{"type":"object","properties":{"content":{"type":"string","minLength":1,"maxLength":5000}},"required":["content"]},"CommentUpdate":{"type":"object","properties":{"resolved":{"type":"boolean"},"content":{"type":"string","minLength":1,"maxLength":5000}}},"CardComment":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"userId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"authorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"authorEmail":{"type":"string","format":"email"},"content":{"type":"string"},"mentions":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"resolvedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"resolvedBy":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"updatedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"editedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"actorVia":{"type":"string","enum":["ui","rest","mcp"],"description":"Surface that created the comment."},"actorToken":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API token name snapshot for agent writers; null for UI."},"system":{"type":"boolean","description":"True on a comment the server wrote before 2026-10-03, when a replaced STATUS/STATO was also kept as a comment carrying the replaced text; no write sets it now (the description history keeps that text). Clients render such a row quietly. Its content cannot be edited by anyone (403, the attributed author included); it can be resolved; only an owner or admin of the board's workspace can delete it."}},"required":["id","cardId","userId","authorName","authorEmail","content","mentions","resolvedAt","resolvedBy","createdAt","updatedAt","editedAt","actorVia","actorToken","system"],"additionalProperties":false},"CommentsResponse":{"type":"object","required":["comments"],"properties":{"comments":{"type":"array","items":{"$ref":"#/components/schemas/CardComment"}}}},"CommentUpdateResponse":{"oneOf":[{"$ref":"#/components/schemas/CardComment"},{"$ref":"#/components/schemas/SuccessResponse"}]},"TokenCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"workspace":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z0-9-]+$"},"scope":{"default":"admin","type":"string","enum":["read","write","admin"]},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["name"]},"GuidanceGrantCreate":{"type":"object","properties":{"workspace":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z0-9-]+$","description":"The workspace whose guidance card the token may write. The caller must be an owner or admin of it; a workspace-bound token can only be allowed for its own workspace."},"durationMinutes":{"default":60,"description":"How long the grant lasts, in minutes: 5 to 1440 (a day), default 60.","type":"integer","minimum":5,"maximum":1440}},"required":["workspace"]},"GuidanceWriteGrant":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"tokenId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"workspace":{"type":"string"},"grantedBy":{"type":"object","properties":{"id":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},"grantedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"status":{"type":"string","enum":["active","expired","revoked"]}},"required":["id","tokenId","workspace","grantedBy","grantedAt","expiresAt","revokedAt","status"],"additionalProperties":false},"ApiToken":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"type":"string"},"prefix":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"scope":{"type":"string","enum":["read","write","admin"]},"workspaceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"grantId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}],"description":"OAuth grant id when kind is oauth; null for personal tokens."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["id","name","prefix","kind","scope","workspaceId","clientId","grantId","expiresAt","lastUsedAt","createdAt","revokedAt"],"additionalProperties":false},"ApiTokenWithGrants":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"type":"string"},"prefix":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"scope":{"type":"string","enum":["read","write","admin"]},"workspaceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"grantId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}],"description":"OAuth grant id when kind is oauth; null for personal tokens."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"guidanceGrants":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"tokenId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"workspace":{"type":"string"},"grantedBy":{"type":"object","properties":{"id":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"name":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name"],"additionalProperties":false},"grantedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"status":{"type":"string","enum":["active","expired","revoked"]}},"required":["id","tokenId","workspace","grantedBy","grantedAt","expiresAt","revokedAt","status"],"additionalProperties":false},"description":"The token's guidance write grants that are not revoked — active or expired, newest first. A grant lets this token write the workspace guidance card until it expires or is revoked (Settings → API tokens → Allow guidance writes)."}},"required":["id","name","prefix","kind","scope","workspaceId","clientId","grantId","expiresAt","lastUsedAt","createdAt","revokedAt","guidanceGrants"],"additionalProperties":false},"OAuthProtectedResourceMetadata":{"type":"object","properties":{"resource":{"type":"string","format":"uri"},"authorization_servers":{"minItems":1,"type":"array","items":{"type":"string","format":"uri"}},"scopes_supported":{"minItems":1,"type":"array","items":{"type":"string"}},"bearer_methods_supported":{"minItems":1,"type":"array","items":{"type":"string"}}},"required":["resource","authorization_servers","scopes_supported","bearer_methods_supported"],"additionalProperties":{}},"OAuthAuthorizationServerMetadata":{"type":"object","properties":{"issuer":{"type":"string","format":"uri"},"authorization_endpoint":{"type":"string","format":"uri"},"token_endpoint":{"type":"string","format":"uri"},"revocation_endpoint":{"type":"string","format":"uri"},"response_types_supported":{"minItems":1,"type":"array","items":{"type":"string"}},"grant_types_supported":{"minItems":1,"type":"array","items":{"type":"string"}},"code_challenge_methods_supported":{"minItems":1,"type":"array","items":{"type":"string"}},"token_endpoint_auth_methods_supported":{"minItems":1,"type":"array","items":{"type":"string"}},"token_endpoint_auth_signing_alg_values_supported":{"minItems":1,"type":"array","items":{"type":"string"},"description":"JWS algorithms accepted for private_key_jwt client assertions (ES256, RS256, PS256, EdDSA)."},"revocation_endpoint_auth_methods_supported":{"minItems":1,"type":"array","items":{"type":"string"}},"revocation_endpoint_auth_signing_alg_values_supported":{"minItems":1,"type":"array","items":{"type":"string"}},"scopes_supported":{"minItems":1,"type":"array","items":{"type":"string"}},"client_id_metadata_document_supported":{"type":"boolean"},"authorization_response_iss_parameter_supported":{"type":"boolean"}},"required":["issuer","authorization_endpoint","token_endpoint","revocation_endpoint","response_types_supported","grant_types_supported","code_challenge_methods_supported","token_endpoint_auth_methods_supported","token_endpoint_auth_signing_alg_values_supported","revocation_endpoint_auth_methods_supported","revocation_endpoint_auth_signing_alg_values_supported","scopes_supported","client_id_metadata_document_supported","authorization_response_iss_parameter_supported"],"additionalProperties":{}},"OAuthTokenResponse":{"type":"object","properties":{"access_token":{"type":"string"},"token_type":{"type":"string","enum":["Bearer"],"description":"Always `Bearer`, spelled as RFC 6750 registers it; RFC 6749 §5.1 has clients compare the value case-insensitively."},"expires_in":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991},"refresh_token":{"type":"string"},"scope":{"type":"string","enum":["read","write","admin"]}},"required":["access_token","token_type","expires_in","refresh_token","scope"],"additionalProperties":{}},"OAuthErrorResponse":{"type":"object","properties":{"error":{"type":"string","description":"The OAuth error code. Tre answers one of `invalid_request`, `invalid_client`, `invalid_grant`, `unsupported_grant_type`, `invalid_target`, `server_error`. `invalid_target` is RFC 8707 §2's, for a token asked for a `resource` other than this server's MCP endpoint; `server_error`, which RFC 6749 §4.1.2.1 defines for the authorization endpoint, answers a 500 or a 503; the others are RFC 6749 §5.2 codes, and a 429 answers `invalid_request`. A string rather than an enum: OAuth error codes are an extensible registry."},"error_description":{"type":"string","pattern":"^[\\x20-\\x21\\x23-\\x5B\\x5D-\\x7E]+$","description":"Human-readable, in the character set RFC 6749 allows (printable ASCII but `\"` and `\\`). A form field that fails validation is named as `<field> is missing` or `<field> is invalid`."}},"required":["error","error_description"],"additionalProperties":{}},"OAuthRevokeResponse":{"type":"object","properties":{},"additionalProperties":false,"description":"Always empty: RFC 7009 carries the outcome in the status code alone."},"TokenCreationResult":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"type":"string"},"prefix":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"scope":{"type":"string","enum":["read","write","admin"]},"workspaceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"grantId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}],"description":"OAuth grant id when kind is oauth; null for personal tokens."},"expiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"plaintext":{"type":"string","pattern":"^tre_pat_"}},"required":["id","name","prefix","kind","scope","workspaceId","clientId","grantId","expiresAt","lastUsedAt","createdAt","revokedAt","plaintext"],"additionalProperties":false},"TokensResponse":{"type":"object","required":["tokens"],"properties":{"tokens":{"type":"array","items":{"$ref":"#/components/schemas/ApiTokenWithGrants"}}}},"ConnectedApp":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"clientId":{"type":"string","description":"CIMD URL of the OAuth client."},"clientName":{"type":"string"},"workspace":{"type":"string","description":"Workspace slug the grant is bound to."},"scope":{"type":"string","enum":["read","write","admin"]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"Last token mint for this grant (the code exchange or a refresh), not the last MCP call."}},"required":["id","clientId","clientName","workspace","scope","createdAt","lastUsedAt"],"additionalProperties":false},"ConnectedAppsResponse":{"type":"object","required":["apps"],"properties":{"apps":{"type":"array","items":{"$ref":"#/components/schemas/ConnectedApp"}}}},"HealthReport":{"type":"object","properties":{"status":{"type":"string","enum":["ok"]},"db":{"type":"string","enum":["ok"]},"commit":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"The commit this deployment was built from; null outside a platform build."}},"required":["status","db","commit"],"additionalProperties":false},"WorkspaceCreate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80}},"required":["name"]},"WorkspaceUpdate":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"slug":{"type":"string","minLength":1,"maxLength":60}}},"WorkspaceDeleteConfirm":{"type":"object","properties":{"confirmSlug":{"type":"string","minLength":1}},"required":["confirmSlug"]},"OwnerTransfer":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"required":["userId"]},"Workspace":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"slug":{"type":"string"},"name":{"type":"string"}},"required":["id","slug","name"],"additionalProperties":false},"WorkspaceCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"slug":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","enum":["owner"]}},"required":["id","slug","name","role"],"additionalProperties":false},"WorkspaceInvite":{"type":"object","properties":{"email":{"format":"email","type":"string"},"role":{"default":"member","type":"string","enum":["owner","admin","member"]}},"required":["email"]},"WorkspaceMemberUpdate":{"type":"object","properties":{"role":{"type":"string","enum":["owner","admin","member"]}},"required":["role"]},"WorkspaceMember":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"email":{"type":"string","format":"email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"image":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","enum":["owner","admin","member"]},"joinedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["userId","email","name","image","role","joinedAt"],"additionalProperties":false},"WorkspaceInvitation":{"type":"object","properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["owner","admin","member"]},"invitedByEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["email","role","invitedByEmail","createdAt"],"additionalProperties":false},"WorkspacePeopleResponse":{"type":"object","properties":{"members":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"email":{"type":"string","format":"email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"image":{"anyOf":[{"type":"string"},{"type":"null"}]},"role":{"type":"string","enum":["owner","admin","member"]},"joinedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["userId","email","name","image","role","joinedAt"],"additionalProperties":false}},"invitations":{"type":"array","items":{"type":"object","properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["owner","admin","member"]},"invitedByEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["email","role","invitedByEmail","createdAt"],"additionalProperties":false}},"yourRole":{"type":"string","enum":["owner","admin","member"]}},"required":["members","invitations","yourRole"],"additionalProperties":false},"WorkspaceInvitationCreated":{"type":"object","properties":{"email":{"type":"string","format":"email"},"role":{"type":"string","enum":["owner","admin","member"]},"accepted":{"type":"boolean","description":"True when the address already had an account and joined immediately."}},"required":["email","role","accepted"],"additionalProperties":false},"PublicUser":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string","format":"email"},"image":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","name","email","image"],"additionalProperties":false},"UsersResponse":{"type":"object","required":["users"],"properties":{"users":{"type":"array","items":{"$ref":"#/components/schemas/PublicUser"}}}},"MeWorkspace":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]}},"required":["slug","name","role"],"additionalProperties":false},"Me":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"email":{"type":"string","format":"email"},"image":{"anyOf":[{"type":"string"},{"type":"null"}]},"workspaces":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]}},"required":["slug","name","role"],"additionalProperties":false}},"token":{"type":"object","properties":{"name":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"scope":{"type":"string","enum":["read","write","admin"]},"workspace":{"anyOf":[{"type":"string"},{"type":"null"}]},"expiresAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["name","kind","scope","workspace","expiresAt"],"additionalProperties":false,"description":"Present when a bearer token is calling: its name, kind, scope ceiling, audience workspace slug (null = every workspace) and expiry (null = never)."}},"required":["id","workspaces"],"additionalProperties":false},"AccountDeleteConfirm":{"type":"object","properties":{"confirmEmail":{"format":"email","type":"string"}},"required":["confirmEmail"]},"AccountExport":{"type":"object","properties":{"exportedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"email":{"type":"string","format":"email"},"name":{"anyOf":[{"type":"string"},{"type":"null"}]},"image":{"anyOf":[{"type":"string"},{"type":"null"}]},"trialStartedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"When the person's one free trial began (their first workspace on a billing-enabled installation); null while it is still theirs to use, and always null on a self-hosted installation."},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","email","name","image","trialStartedAt","createdAt"],"additionalProperties":false},"workspaces":{"type":"array","items":{"type":"object","properties":{"slug":{"type":"string"},"name":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]}},"required":["slug","name","role"],"additionalProperties":false}},"invitations":{"type":"array","items":{"type":"object","properties":{"workspaceSlug":{"type":"string"},"role":{"type":"string","enum":["owner","admin","member"]},"invitedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"acceptedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["workspaceSlug","role","invitedAt","acceptedAt"],"additionalProperties":false}},"cardsCreated":{"type":"array","items":{"type":"object","properties":{"cardKey":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"workspaceSlug":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"deletedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}],"description":"Set while the card is in the trash; null for a live card."}},"required":["cardKey","title","description","workspaceSlug","createdAt","deletedAt"],"additionalProperties":false}},"comments":{"type":"array","items":{"type":"object","properties":{"cardKey":{"type":"string"},"content":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["cardKey","content","createdAt"],"additionalProperties":false}},"checklistItemsAssigned":{"type":"array","items":{"type":"object","properties":{"cardKey":{"type":"string"},"text":{"type":"string"},"completed":{"type":"boolean"}},"required":["cardKey","text","completed"],"additionalProperties":false}},"cardsAssigned":{"type":"array","items":{"type":"object","properties":{"cardKey":{"type":"string"},"title":{"type":"string"}},"required":["cardKey","title"],"additionalProperties":false}},"apiTokens":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"prefix":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"clientId":{"anyOf":[{"type":"string"},{"type":"null"}]},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"lastUsedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"guidanceGrants":{"type":"array","items":{"type":"object","properties":{"workspaceSlug":{"type":"string"},"grantedAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"revokedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]}},"required":["workspaceSlug","grantedAt","expiresAt","revokedAt"],"additionalProperties":false},"description":"Every guidance write grant ever made on the token, revoked ones included, oldest first."}},"required":["name","prefix","kind","clientId","createdAt","lastUsedAt","revokedAt","guidanceGrants"],"additionalProperties":false},"description":"Every token row the account owns, personal and OAuth alike; kind and clientId say which application an OAuth row was minted for. Never a secret."},"activity":{"type":"array","items":{"type":"object","properties":{"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"workspaceSlug":{"type":"string"},"boardSlug":{"type":"string"},"verb":{"type":"string","description":"Catalog verb, e.g. `card.created`."},"cardKey":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Null for events that name no card (board and list verbs)."},"via":{"type":"string","description":"The surface the action came through: 'ui', 'rest' or 'mcp'."},"token":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Name of the API token used, snapshotted at write time; null for a session."},"by":{"type":"object","properties":{"user":{"anyOf":[{"type":"string"},{"type":"null"}]},"via":{"type":"string"},"token":{"type":"string"},"agent":{"description":"Present when the ledger recorded a token id. The agent name is snapshotted at write time; user remains the delegating human. Historical name-only events have no agent. OAuth tokens also carry `client` (the CIMD URL).","type":"object","properties":{"profile":{"type":"string","enum":["ai_agent"]},"tokenId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"client":{"description":"CIMD URL when kind is oauth and the token row still names a client.","type":"string"}},"required":["profile","tokenId","name","kind"],"additionalProperties":false}},"required":["user","via"],"additionalProperties":false,"description":"Who did it. `user` is null for a deleted account or a member who never set a display name — never fall back to an email here."},"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{},"description":"The catalogued record as written — excerpts, never whole documents. An event you actored can still quote another member's prose: the removed lines of a description diff, a title, a checklist item's text, a display name. The board-readability filter on this whole section, not the actor column, is what makes that safe to export — do not relax it."}},"required":["at","workspaceSlug","boardSlug","verb","cardKey","via","token","by","payload"],"additionalProperties":false},"description":"Events the caller themselves actored, oldest first, limited to what is still on the ledger (older activity ages out) and to boards the caller can read today. Another member's events are never here."}},"required":["exportedAt","user","workspaces","invitations","cardsCreated","comments","checklistItemsAssigned","cardsAssigned","apiTokens","activity"],"additionalProperties":false,"description":"The caller's own data: profile, memberships, invitations, authored cards and comments, assignments, API-token metadata (never token secrets), and own-actored activity still on the events ledger. Every content section is scoped to what the account can read TODAY and, for a workspace-bound bearer, to its audience."},"VersionMeta":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"createdBy":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"origin":{"type":"string","enum":["checkpoint","replace"],"description":"How the version came to exist: 'checkpoint' = periodic capture of the editor's pre-save state; 'replace' = content an external rewrite or a restore was about to overwrite."},"authorName":{"anyOf":[{"type":"string"},{"type":"null"}]},"authorEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"actorVia":{"type":"string","enum":["ui","rest","mcp"],"description":"Surface that archived this version."},"actorToken":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"API token name snapshot for agent writers; null for UI."},"statusDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"The date of the STATUS/STATO (or UPDATED/AGGIORNATO) line this version's text carried, read as the summary view reads statusDate; null when the text had no dated line. Locate the version valid on a date from the list, then read that one."}},"required":["id","cardId","createdAt","createdBy","origin","authorName","authorEmail","actorVia","actorToken","statusDate"],"additionalProperties":false},"HistoryResponse":{"type":"object","required":["versions"],"properties":{"versions":{"type":"array","items":{"$ref":"#/components/schemas/VersionMeta"}}}},"StateResponse":{"type":"object","properties":{"text":{"type":"string","description":"Plain description text decoded from this version's CRDT snapshot — read this to see what the version said."},"state":{"type":"string","description":"Base64-encoded Yjs CRDT update. Opaque outside the editor, which uses it to render a preview of this version; restoring re-reads the snapshot server-side and needs no body. Use `text` to read the content."}},"required":["text","state"],"additionalProperties":false},"YjsStateResponse":{"type":"object","properties":{"state":{"type":"string"},"epoch":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Lineage epoch of the CRDT document. Bumps only when the server rebuilds the document at load (a pre-2026-09-16 format-1 document, one still holding a `\\r`, or one whose stored state reached 32 KB); an external rewrite or a restore reaches the document as an update under the same epoch. Saves must carry it back and get 409 when it is stale."}},"required":["state","epoch"],"additionalProperties":false},"SuccessResponse":{"type":"object","properties":{"success":{"type":"boolean","const":true}},"required":["success"],"additionalProperties":false},"RelayTokenRequest":{"type":"object","properties":{"boardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"required":["boardId"]},"RelayTokenResponse":{"type":"object","properties":{"token":{"type":"string","minLength":1},"url":{"type":"string","minLength":1},"expiresAt":{"type":"integer","exclusiveMinimum":0,"maximum":9007199254740991}},"required":["token","url","expiresAt"],"additionalProperties":false},"YjsStateUpdate":{"type":"object","properties":{"state":{"type":"string","minLength":1,"maxLength":500000},"description":{"type":"string","maxLength":2000},"epoch":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["state","epoch"]},"TimelinePayload":{"type":"object","properties":{"cards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"boardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"boardSlug":{"type":"string"},"listId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"title":{"type":"string"},"color":{"type":"string"},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"assigneeUserIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"subtasks":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"cardId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"title":{"type":"string"},"startDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"endDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"scheduleState":{"type":"string","enum":["unclassified","planned","suspended","cancelled"],"description":"Meaning of the retained schedule. Unclassified means its intent has not been reviewed; suspended/cancelled retain the plan for retrospective comparison."},"actualStartDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed start, explicitly recorded from evidence. Independent of the schedule; null means unknown, never not started."},"actualEndDate":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}],"description":"Observed end, explicitly recorded from evidence. May fall outside the plan. Null means unknown, never incomplete."},"order":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"color":{"type":"string"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},"required":["id","cardId","title","startDate","endDate","scheduleState","actualStartDate","actualEndDate","order","color","createdAt"],"additionalProperties":false}}},"required":["id","boardId","boardSlug","listId","title","color","startDate","endDate","scheduleState","actualStartDate","actualEndDate","assigneeUserIds","subtasks"],"additionalProperties":false}}},"required":["cards"],"additionalProperties":false},"EventActor":{"type":"object","properties":{"user":{"anyOf":[{"type":"string"},{"type":"null"}]},"via":{"type":"string"},"token":{"type":"string"},"agent":{"description":"Present when the ledger recorded a token id. The agent name is snapshotted at write time; user remains the delegating human. Historical name-only events have no agent. OAuth tokens also carry `client` (the CIMD URL).","type":"object","properties":{"profile":{"type":"string","enum":["ai_agent"]},"tokenId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"client":{"description":"CIMD URL when kind is oauth and the token row still names a client.","type":"string"}},"required":["profile","tokenId","name","kind"],"additionalProperties":false}},"required":["user","via"],"additionalProperties":false,"description":"Who did it. `user` is null for a deleted account or a member who never set a display name — never fall back to an email here."},"Event":{"type":"object","properties":{"seq":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Strictly increasing per workspace."},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"workspace":{"type":"string","description":"Workspace slug."},"verb":{"type":"string","description":"A catalogued verb, e.g. `card.created`."},"board":{"type":"string","description":"Board slug."},"card":{"description":"Card cardKey, when this verb names one.","type":"string"},"by":{"type":"object","properties":{"user":{"anyOf":[{"type":"string"},{"type":"null"}]},"via":{"type":"string"},"token":{"type":"string"},"agent":{"description":"Present when the ledger recorded a token id. The agent name is snapshotted at write time; user remains the delegating human. Historical name-only events have no agent. OAuth tokens also carry `client` (the CIMD URL).","type":"object","properties":{"profile":{"type":"string","enum":["ai_agent"]},"tokenId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"client":{"description":"CIMD URL when kind is oauth and the token row still names a client.","type":"string"}},"required":["profile","tokenId","name","kind"],"additionalProperties":false}},"required":["user","via"],"additionalProperties":false,"description":"Who did it. `user` is null for a deleted account or a member who never set a display name — never fall back to an email here."}},"required":["seq","at","workspace","verb","board","by"],"additionalProperties":{},"description":"One row from the events ledger. `board` is always the board SLUG and `card` (when the verb has one) the stable cardKey — never the UUIDs the underlying columns carry. Every other verb-specific field (e.g. `name`, `list`, `text`, `changes`) rides along beside these on the same object; the catalogue lives in the agentic-reading design doc, not here."},"BriefList":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$","description":"List id — what createCard wants."},"name":{"type":"string"},"cards":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["id","name","cards"],"additionalProperties":false},"BriefBoard":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$","description":"Board id — what listCards wants."},"board":{"type":"string","description":"Board slug."},"key":{"type":"string","description":"cardKey prefix."},"name":{"type":"string"},"lists":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$","description":"List id — what createCard wants."},"name":{"type":"string"},"cards":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["id","name","cards"],"additionalProperties":false}}},"required":["id","board","key","name","lists"],"additionalProperties":false},"BriefWorkspace":{"type":"object","properties":{"workspace":{"type":"string"},"boards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$","description":"Board id — what listCards wants."},"board":{"type":"string","description":"Board slug."},"key":{"type":"string","description":"cardKey prefix."},"name":{"type":"string"},"lists":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$","description":"List id — what createCard wants."},"name":{"type":"string"},"cards":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["id","name","cards"],"additionalProperties":false}}},"required":["id","board","key","name","lists"],"additionalProperties":false}},"stale":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Cards on the non-archived boards you can read that the lint reports as stale_status: open cards (not closed — actualEndDate null and scheduleState not cancelled) whose dated STATUS/UPDATED is more than 14 days old (W3-D2). Since 2026-10-15 exactly the lint view's own count (before, it counted closed cards too). Those updated within the last 30 days are in attention, the others in inventory."},"inventory":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"OPEN cards on the non-archived boards you can read carrying at least one lint finding that attention does not count, and none it does (since 2026-10-15): the audit a session is not being asked to do now — a stale line on a card nobody touched for 30 days, a legacy card without a STATUS, a bare orphan. Disjoint from attention.count; the lint view per board lists them."},"attention":{"type":"object","properties":{"count":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Cards on the non-archived boards you can read carrying at least one ACTIONABLE lint finding (W3-D5, calibrated 2026-09-05 and 2026-10-15): unresolved_reference, oversize_description, duplicate_status, overdue, stale_verification (the last two since 2026-09-26) and status_log (since 2026-10-15) at any age; stale_status only when the card was updated within the last 30 days; missing_status only when it was updated within the last 14 days. orphan never counts; a closed card (actualEndDate set, or scheduleState cancelled) is never stale_status, missing_status, overdue, stale_verification or status_log; the lint view remains the full audit, and `inventory` counts the open cards it names that attention does not. A card on an archived board counts towards none of the three (since 2026-10-15; before, every readable board counted)."},"sample":{"maxItems":5,"type":"array","items":{"type":"string"},"description":"At most five cardKeys with actionable findings, most recently updated first."}},"required":["count","sample"],"additionalProperties":false},"guidance":{"type":"object","properties":{"cardKey":{"type":"string"},"excerpt":{"type":"string","description":"The oldest non-archived kind: guidance card's description, first 280 characters (W3-D7). Absent from BriefWorkspace when the workspace has none."}},"required":["cardKey","excerpt"],"additionalProperties":false}},"required":["workspace","boards","stale","inventory","attention"],"additionalProperties":false},"BriefGuidance":{"type":"object","properties":{"cardKey":{"type":"string"},"excerpt":{"type":"string","description":"The oldest non-archived kind: guidance card's description, first 280 characters (W3-D7). Absent from BriefWorkspace when the workspace has none."}},"required":["cardKey","excerpt"],"additionalProperties":false},"BriefAttention":{"type":"object","properties":{"count":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Cards on the non-archived boards you can read carrying at least one ACTIONABLE lint finding (W3-D5, calibrated 2026-09-05 and 2026-10-15): unresolved_reference, oversize_description, duplicate_status, overdue, stale_verification (the last two since 2026-09-26) and status_log (since 2026-10-15) at any age; stale_status only when the card was updated within the last 30 days; missing_status only when it was updated within the last 14 days. orphan never counts; a closed card (actualEndDate set, or scheduleState cancelled) is never stale_status, missing_status, overdue, stale_verification or status_log; the lint view remains the full audit, and `inventory` counts the open cards it names that attention does not. A card on an archived board counts towards none of the three (since 2026-10-15; before, every readable board counted)."},"sample":{"maxItems":5,"type":"array","items":{"type":"string"},"description":"At most five cardKeys with actionable findings, most recently updated first."}},"required":["count","sample"],"additionalProperties":false},"CatchUpBrief":{"type":"object","properties":{"workspaces":{"type":"array","items":{"type":"object","properties":{"workspace":{"type":"string"},"boards":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$","description":"Board id — what listCards wants."},"board":{"type":"string","description":"Board slug."},"key":{"type":"string","description":"cardKey prefix."},"name":{"type":"string"},"lists":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$","description":"List id — what createCard wants."},"name":{"type":"string"},"cards":{"type":"integer","minimum":0,"maximum":9007199254740991}},"required":["id","name","cards"],"additionalProperties":false}}},"required":["id","board","key","name","lists"],"additionalProperties":false}},"stale":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Cards on the non-archived boards you can read that the lint reports as stale_status: open cards (not closed — actualEndDate null and scheduleState not cancelled) whose dated STATUS/UPDATED is more than 14 days old (W3-D2). Since 2026-10-15 exactly the lint view's own count (before, it counted closed cards too). Those updated within the last 30 days are in attention, the others in inventory."},"inventory":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"OPEN cards on the non-archived boards you can read carrying at least one lint finding that attention does not count, and none it does (since 2026-10-15): the audit a session is not being asked to do now — a stale line on a card nobody touched for 30 days, a legacy card without a STATUS, a bare orphan. Disjoint from attention.count; the lint view per board lists them."},"attention":{"type":"object","properties":{"count":{"type":"integer","minimum":0,"maximum":9007199254740991,"description":"Cards on the non-archived boards you can read carrying at least one ACTIONABLE lint finding (W3-D5, calibrated 2026-09-05 and 2026-10-15): unresolved_reference, oversize_description, duplicate_status, overdue, stale_verification (the last two since 2026-09-26) and status_log (since 2026-10-15) at any age; stale_status only when the card was updated within the last 30 days; missing_status only when it was updated within the last 14 days. orphan never counts; a closed card (actualEndDate set, or scheduleState cancelled) is never stale_status, missing_status, overdue, stale_verification or status_log; the lint view remains the full audit, and `inventory` counts the open cards it names that attention does not. A card on an archived board counts towards none of the three (since 2026-10-15; before, every readable board counted)."},"sample":{"maxItems":5,"type":"array","items":{"type":"string"},"description":"At most five cardKeys with actionable findings, most recently updated first."}},"required":["count","sample"],"additionalProperties":false},"guidance":{"type":"object","properties":{"cardKey":{"type":"string"},"excerpt":{"type":"string","description":"The oldest non-archived kind: guidance card's description, first 280 characters (W3-D7). Absent from BriefWorkspace when the workspace has none."}},"required":["cardKey","excerpt"],"additionalProperties":false}},"required":["workspace","boards","stale","inventory","attention"],"additionalProperties":false}},"recent":{"type":"array","items":{"type":"object","properties":{"seq":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Strictly increasing per workspace."},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"workspace":{"type":"string","description":"Workspace slug."},"verb":{"type":"string","description":"A catalogued verb, e.g. `card.created`."},"board":{"type":"string","description":"Board slug."},"card":{"description":"Card cardKey, when this verb names one.","type":"string"},"by":{"type":"object","properties":{"user":{"anyOf":[{"type":"string"},{"type":"null"}]},"via":{"type":"string"},"token":{"type":"string"},"agent":{"description":"Present when the ledger recorded a token id. The agent name is snapshotted at write time; user remains the delegating human. Historical name-only events have no agent. OAuth tokens also carry `client` (the CIMD URL).","type":"object","properties":{"profile":{"type":"string","enum":["ai_agent"]},"tokenId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"client":{"description":"CIMD URL when kind is oauth and the token row still names a client.","type":"string"}},"required":["profile","tokenId","name","kind"],"additionalProperties":false}},"required":["user","via"],"additionalProperties":false,"description":"Who did it. `user` is null for a deleted account or a member who never set a display name — never fall back to an email here."}},"required":["seq","at","workspace","verb","board","by"],"additionalProperties":{},"description":"One row from the events ledger. `board` is always the board SLUG and `card` (when the verb has one) the stable cardKey — never the UUIDs the underlying columns carry. Every other verb-specific field (e.g. `name`, `list`, `text`, `changes`) rides along beside these on the same object; the catalogue lives in the agentic-reading design doc, not here."}},"cursor":{"type":"string"}},"required":["workspaces","recent","cursor"],"additionalProperties":false},"CatchUpDelta":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"seq":{"type":"integer","minimum":1,"maximum":9007199254740991,"description":"Strictly increasing per workspace."},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"workspace":{"type":"string","description":"Workspace slug."},"verb":{"type":"string","description":"A catalogued verb, e.g. `card.created`."},"board":{"type":"string","description":"Board slug."},"card":{"description":"Card cardKey, when this verb names one.","type":"string"},"by":{"type":"object","properties":{"user":{"anyOf":[{"type":"string"},{"type":"null"}]},"via":{"type":"string"},"token":{"type":"string"},"agent":{"description":"Present when the ledger recorded a token id. The agent name is snapshotted at write time; user remains the delegating human. Historical name-only events have no agent. OAuth tokens also carry `client` (the CIMD URL).","type":"object","properties":{"profile":{"type":"string","enum":["ai_agent"]},"tokenId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"name":{"type":"string"},"kind":{"type":"string","enum":["personal","oauth"]},"client":{"description":"CIMD URL when kind is oauth and the token row still names a client.","type":"string"}},"required":["profile","tokenId","name","kind"],"additionalProperties":false}},"required":["user","via"],"additionalProperties":false,"description":"Who did it. `user` is null for a deleted account or a member who never set a display name — never fall back to an email here."}},"required":["seq","at","workspace","verb","board","by"],"additionalProperties":{},"description":"One row from the events ledger. `board` is always the board SLUG and `card` (when the verb has one) the stable cardKey — never the UUIDs the underlying columns carry. Every other verb-specific field (e.g. `name`, `list`, `text`, `changes`) rides along beside these on the same object; the catalogue lives in the agentic-reading design doc, not here."}},"cursor":{"type":"string"},"hasMore":{"type":"boolean","description":"True when unfiltered rows remain beyond this scan. Events on boards the caller cannot read are filtered out AFTER the scan, so a page can carry fewer events than `limit` — even zero — while this is true."},"resynced":{"description":"Workspace slugs, sorted, whose cursor position had fallen off the ledger (retention) and was restarted from the oldest event still retained. The events between are unrecoverable; every other workspace in this same response is unaffected, so keep using the returned cursor rather than restarting from the brief. Absent — not an empty array — when no workspace was resynced.","minItems":1,"type":"array","items":{"type":"string"}}},"required":["events","cursor","hasMore"],"additionalProperties":false},"CatchUpResponse":{"oneOf":[{"$ref":"#/components/schemas/CatchUpBrief"},{"$ref":"#/components/schemas/CatchUpDelta"}]},"AccessRequestInput":{"type":"object","properties":{"email":{"format":"email","type":"string"},"agents":{"default":[],"description":"Which agents the person runs, any of: claude-code, codex, cursor, openclaw, chatgpt, other.","maxItems":6,"type":"array","items":{"type":"string","enum":["claude-code","codex","cursor","openclaw","chatgpt","other"]}},"note":{"description":"Up to 280 characters: what the person would use Tre for.","type":"string","maxLength":280},"website":{"type":"string","maxLength":200}},"required":["email"],"additionalProperties":false},"AccessRequestReceipt":{"type":"object","properties":{"status":{"type":"string","enum":["received"]}},"required":["status"],"additionalProperties":false},"BillingCheckout":{"type":"object","properties":{"plan":{"type":"string","enum":["solo","team"]}},"required":["plan"]},"BillingSessionResponse":{"type":"object","properties":{"url":{"type":"string","format":"uri","description":"Hosted Stripe page to redirect the browser to."}},"required":["url"],"additionalProperties":false},"WebhookReceipt":{"type":"object","properties":{"received":{"type":"boolean","const":true},"replay":{"description":"True when this event id was already processed (idempotent replay).","type":"boolean","const":true}},"required":["received"],"additionalProperties":false},"AccessRequestStatusUpdate":{"type":"object","properties":{"status":{"type":"string","enum":["new","invited","declined"]}},"required":["status"]},"OpsCredentialRevoke":{"type":"object","properties":{"reasonCode":{"type":"string","enum":["security_incident","customer_request","acceptable_use"]},"reference":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._:#/-]{0,63}$"}},"required":["reasonCode"]},"OpsProposalApprove":{"type":"object","properties":{"confirmSlug":{"type":"string","minLength":1},"acknowledgeStale":{"default":false,"type":"boolean"},"reference":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._:#/-]{0,63}$"}}},"OpsProposalReject":{"type":"object","properties":{"note":{"type":"string","maxLength":500}}},"WorkspaceSuspend":{"type":"object","properties":{"reasonCode":{"type":"string","enum":["acceptable_use","security_incident","payment_dispute","customer_request"]},"reviewOn":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},"noticeSentOn":{"anyOf":[{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"},{"type":"null"}]},"confirmSlug":{"type":"string","minLength":1},"reference":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._:#/-]{0,63}$"}},"required":["reasonCode","noticeSentOn","confirmSlug"]},"WorkspaceSuspensionLift":{"type":"object","properties":{"reference":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._:#/-]{0,63}$"}}},"OpsAgentOverview":{"type":"object","properties":{"app":{"type":"string","const":"tre"},"contractVersion":{"type":"number","const":1},"strip":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{"anyOf":[{"type":"number"},{"type":"string"},{"type":"boolean"}]}},"attention":{"type":"array","items":{"type":"object","properties":{"kind":{"type":"string"},"level":{"type":"string","enum":["red","amber"]},"count":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991},"targetIds":{"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},"consoleUrl":{"type":"string"}},"required":["kind","level","count","targetIds","consoleUrl"],"additionalProperties":false}},"proposals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"proposedBy":{"type":"string"},"action":{"type":"string","enum":["access_request.invited","access_request.declined","access_request.reopened","token.revoked","grant.revoked","sessions.revoked","workspace.suspended","workspace.suspension_lifted"]},"accountId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"accountSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"subjectEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"targetId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"reasonCode":{"type":"string","enum":["customer_request","data_subject_request","security_incident","acceptable_use","payment_dispute","housekeeping"]},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"rationale":{"type":"string"},"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"status":{"type":"string","enum":["open","approved","rejected","expired","superseded"]},"stale":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"decidedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"decidedBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"decisionNote":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","createdAt","proposedBy","action","accountId","accountSlug","subjectUserId","subjectEmail","targetId","reasonCode","reference","rationale","payload","expiresAt","status","stale","decidedAt","decidedBy","decisionNote"],"additionalProperties":false}}},"required":["app","contractVersion","strip","attention","proposals"],"additionalProperties":false},"OpsAgentList":{"type":"object","properties":{"view":{"type":"string","enum":["people","accounts","requests","proposals"]},"lens":{"type":"string"},"rows":{"type":"array","items":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}}},"total":{"type":"integer","minimum":-9007199254740991,"maximum":9007199254740991}},"required":["view","lens","rows","total"],"additionalProperties":false},"OpsAgentGet":{"type":"object","properties":{"kind":{"type":"string","enum":["person","account","request","proposal"]},"accessNow":{"type":"string"},"detail":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"proposals":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"createdAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"proposedBy":{"type":"string"},"action":{"type":"string","enum":["access_request.invited","access_request.declined","access_request.reopened","token.revoked","grant.revoked","sessions.revoked","workspace.suspended","workspace.suspension_lifted"]},"accountId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"accountSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"subjectEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"targetId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"reasonCode":{"type":"string","enum":["customer_request","data_subject_request","security_incident","acceptable_use","payment_dispute","housekeeping"]},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"rationale":{"type":"string"},"payload":{"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"expiresAt":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"status":{"type":"string","enum":["open","approved","rejected","expired","superseded"]},"stale":{"anyOf":[{"type":"boolean"},{"type":"null"}]},"decidedAt":{"anyOf":[{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},{"type":"null"}]},"decidedBy":{"anyOf":[{"type":"string"},{"type":"null"}]},"decisionNote":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","createdAt","proposedBy","action","accountId","accountSlug","subjectUserId","subjectEmail","targetId","reasonCode","reference","rationale","payload","expiresAt","status","stale","decidedAt","decidedBy","decisionNote"],"additionalProperties":false}},"log":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"operatorLabel":{"type":"string"},"via":{"type":"string","enum":["ui","cli","sql","agent_proposal"]},"action":{"type":"string","enum":["access_request.invited","access_request.declined","access_request.reopened","access_request.deleted","token.revoked","grant.revoked","sessions.revoked","workspace.suspended","workspace.suspension_lifted","account.closed","cli.invite","workspace.owner_restored","agent_token.minted"]},"reasonCode":{"type":"string","enum":["customer_request","data_subject_request","security_incident","acceptable_use","payment_dispute","housekeeping"]},"workspaceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"workspaceSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"subjectEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"targetId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"detail":{"type":"object","propertyNames":{"type":"string","pattern":"^[a-zA-Z][a-zA-Z0-9]{0,39}$"},"additionalProperties":{"anyOf":[{"type":"string","maxLength":64},{"type":"number"},{"type":"boolean"},{"type":"null"}]}},"proposalId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"proposedBy":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","at","operatorLabel","via","action","reasonCode","workspaceId","workspaceSlug","subjectUserId","subjectEmail","targetId","reference","detail","proposalId","proposedBy"],"additionalProperties":false}}},"required":["kind","detail","proposals","log"],"additionalProperties":false},"OpsAgentLog":{"type":"object","properties":{"rows":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"at":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"},"operatorLabel":{"type":"string"},"via":{"type":"string","enum":["ui","cli","sql","agent_proposal"]},"action":{"type":"string","enum":["access_request.invited","access_request.declined","access_request.reopened","access_request.deleted","token.revoked","grant.revoked","sessions.revoked","workspace.suspended","workspace.suspension_lifted","account.closed","cli.invite","workspace.owner_restored","agent_token.minted"]},"reasonCode":{"type":"string","enum":["customer_request","data_subject_request","security_incident","acceptable_use","payment_dispute","housekeeping"]},"workspaceId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"workspaceSlug":{"anyOf":[{"type":"string"},{"type":"null"}]},"subjectUserId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"subjectEmail":{"anyOf":[{"type":"string","format":"email"},{"type":"null"}]},"targetId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"reference":{"anyOf":[{"type":"string"},{"type":"null"}]},"detail":{"type":"object","propertyNames":{"type":"string","pattern":"^[a-zA-Z][a-zA-Z0-9]{0,39}$"},"additionalProperties":{"anyOf":[{"type":"string","maxLength":64},{"type":"number"},{"type":"boolean"},{"type":"null"}]}},"proposalId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"proposedBy":{"anyOf":[{"type":"string"},{"type":"null"}]}},"required":["id","at","operatorLabel","via","action","reasonCode","workspaceId","workspaceSlug","subjectUserId","subjectEmail","targetId","reference","detail","proposalId","proposedBy"],"additionalProperties":false}}},"required":["rows"],"additionalProperties":false},"OpsPropose":{"type":"object","properties":{"action":{"type":"string","enum":["access_request.invited","access_request.declined","access_request.reopened","token.revoked","grant.revoked","sessions.revoked","workspace.suspended","workspace.suspension_lifted"]},"accountId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"subjectUserId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"targetId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"reasonCode":{"type":"string","enum":["customer_request","data_subject_request","security_incident","acceptable_use","payment_dispute","housekeeping"]},"reference":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._:#/-]{0,63}$"},"rationale":{"type":"string","minLength":1,"maxLength":2000},"payload":{"default":{},"type":"object","propertyNames":{"type":"string"},"additionalProperties":{}},"expiresInDays":{"default":7,"type":"integer","minimum":1,"maximum":30}},"required":["action","reasonCode","rationale"]},"OpsAgentProposeResult":{"type":"object","properties":{"proposalId":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},"status":{"type":"string","enum":["open","approved","rejected","expired","superseded"]},"supersededId":{"anyOf":[{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"},{"type":"null"}]},"consoleUrl":{"type":"string"}},"required":["proposalId","status","supersededId","consoleUrl"],"additionalProperties":false}}},"paths":{"/api/boards":{"get":{"operationId":"listBoards","summary":"List visible boards","tags":["Boards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"workspace","in":"query","required":false,"description":"Workspace slug. Omit to span every workspace visible to the caller; a workspace-bound token sees only its audience.","schema":{"type":"string"}},{"name":"slug","in":"query","required":false,"description":"Case-insensitive exact slug filter.","schema":{"type":"string"}},{"name":"name","in":"query","required":false,"description":"Case-insensitive exact name filter.","schema":{"type":"string"}},{"name":"includeArchived","in":"query","required":false,"description":"Also list the archived boards the caller is an explicit member of — the rule `GET /api/boards/{boardId}` applies. Default false.","schema":{"type":"boolean"}}]},"post":{"operationId":"createBoard","summary":"Create a board","tags":["Boards"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Board"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"A private board is any workspace member's to create; a shared one takes an owner or admin of the workspace. A read-only workspace — suspended by the operator, or with a trial that ran out, a canceled subscription or no plan chosen — answers 403 and creates nothing: the message says which.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/boards/reorder":{"post":{"operationId":"reorderBoards","summary":"Reorder boards editable by the caller","tags":["Boards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardReorder"}}}}}},"/api/boards/{boardId}":{"parameters":[{"name":"boardId","in":"path","required":true,"description":"Board UUID.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getBoard","summary":"Get a readable board and caller role","tags":["Boards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardWithRole"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"One readable board plus the caller's own `role` on it. While the workspace is read-only — suspended by the operator, or with a trial that ran out, a canceled subscription or no plan chosen — `role` is `viewer` for every member and board writes answer 403 `Editor permissions required`. An archived board stays readable by its explicit members (`archivedAt` set) although `GET /api/boards` no longer lists it — archiving is listing, not privacy. Every board id the caller cannot read — private, archived, another workspace's, unknown — answers the one 403 `No board with this id, or you are not a member of it`, which never says whether the board exists."},"patch":{"operationId":"updateBoard","summary":"Update board name or privacy","tags":["Boards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Board"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardUpdate"}}}}},"delete":{"operationId":"archiveBoard","summary":"Archive a board","tags":["Boards"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Soft archive: `archivedAt` is set, nothing is deleted. The board leaves `GET /api/boards` and the brief, keeps its `keyPrefix` reserved, and stays readable by its explicit members through `GET /api/boards/{boardId}` (and its lists and cards), by nobody else. Not restorable from the current UI or the API."}},"/api/boards/{boardId}/background":{"parameters":[{"name":"boardId","in":"path","required":true,"description":"Board UUID.","schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"setBoardBackground","summary":"Set a color/gradient preset or upload a JPEG background","tags":["Boards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Board"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardBackgroundPreset"}},"multipart/form-data":{"schema":{"type":"object","required":["file"],"properties":{"file":{"type":"string","format":"binary","description":"JPEG image, maximum 2 MB."}}}}}}},"delete":{"operationId":"removeBoardBackground","summary":"Remove the board background","tags":["Boards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Board"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/boards/{boardId}/members":{"parameters":[{"name":"boardId","in":"path","required":true,"description":"Board UUID.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listBoardMembers","summary":"List board members (workspace admin role; any token scope)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardMembersResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"post":{"operationId":"addBoardMember","summary":"Add an allowlisted user to a board (workspace admin role and admin token scope)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardMember"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardMemberCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/boards/{boardId}/members/{userId}":{"parameters":[{"name":"boardId","in":"path","required":true,"description":"Board UUID.","schema":{"type":"string","format":"uuid"}},{"name":"userId","in":"path","required":true,"description":"User UUID.","schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateBoardMember","summary":"Change a board member role (admin only)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardMemberUpdate"}}}}},"delete":{"operationId":"removeBoardMember","summary":"Remove a board membership (admin only)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/boards/{boardId}/background/{etag}":{"parameters":[{"name":"boardId","in":"path","required":true,"description":"Board UUID.","schema":{"type":"string","format":"uuid"}},{"name":"etag","in":"path","required":true,"description":"Content hash of the stored image, from `backgroundValue`.","schema":{"type":"string"}}],"get":{"operationId":"getBoardBackground","summary":"Serve an uploaded board background","tags":["Internal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"The background image bytes (uploads are JPEG only).","headers":{"ETag":{"description":"The quoted content hash — the `{etag}` of this path.","schema":{"type":"string"}},"Cache-Control":{"description":"`private, max-age=31536000, immutable`: one URL, one image.","schema":{"type":"string"}}},"content":{"image/jpeg":{"schema":{"type":"string","format":"binary"}}}},"304":{"description":"Not modified: If-None-Match named the current ETag. No body.","headers":{"ETag":{"description":"The quoted content hash — the `{etag}` of this path.","schema":{"type":"string"}},"Cache-Control":{"description":"`private, max-age=31536000, immutable`: one URL, one image.","schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Returns the JPEG bytes for the board background identified by its content hash. Authorized like any board read, and immutably cacheable because the hash changes with the image.","parameters":[{"name":"If-None-Match","in":"header","required":false,"description":"The ETag of a copy already held; the current one answers 304.","schema":{"type":"string"}}],"x-tre-internal":true}},"/api/boards/{boardId}/lists":{"parameters":[{"name":"boardId","in":"path","required":true,"description":"Board UUID.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listBoardLists","summary":"List columns on a readable board","tags":["Lists"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"title","in":"query","required":false,"description":"Case-insensitive exact title filter.","schema":{"type":"string"}}]},"post":{"operationId":"createList","summary":"Create a board column","tags":["Lists"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/List"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/boards/{boardId}/lists/reorder":{"parameters":[{"name":"boardId","in":"path","required":true,"description":"Board UUID.","schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"reorderLists","summary":"Reorder board columns","tags":["Lists"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListReorder"}}}}}},"/api/lists/{listId}":{"parameters":[{"name":"listId","in":"path","required":true,"description":"List UUID.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getList","summary":"Get a column from a readable board","tags":["Lists"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/List"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"patch":{"operationId":"updateList","summary":"Update a column","tags":["Lists"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/List"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ListUpdate"}}}}},"delete":{"operationId":"deleteList","summary":"Delete a column; its cards move to the trash","tags":["Lists"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/boards/{boardId}/cards":{"parameters":[{"name":"boardId","in":"path","required":true,"description":"Board UUID.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"listBoardCards","summary":"List cards on a readable board","tags":["Cards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BoardCardsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Same `titleContains`/`textContains`/`view`/`includeDeleted` contract as MCP `list_cards` (`cardListQuerySchema` in lib/schemas/card.ts validates both). `titleContains` filters server-side, case-insensitively, on card title. `textContains` (W3-D1) matches case-insensitively on title, description, comment bodies, checklist items AND subtask titles — several words mean every word, each anywhere on the card, an `ALIASES:` line searched like any text (since 2026-10-16) — always answers `view=summary` (any other view is refused with 400) and adds `match: { field, snippet }` — the first field holding every word (title, description, comment, checklist, subtask), or, when the words are spread over fields, the first holding one of them, with a snippet of at most 120 characters; combines with `updatedSince` (ISO datetime) and `citing` (a cardKey: cards whose citation graph points at it) — both of which also apply on their own, at every `view` but `lint`, which answers every card that needs care and ignores the filters. `view` defaults to `full` — today's complete card payload, byte-for-byte unchanged. `view=summary` returns only `id`, `cardKey`, `title`, `listId`, `startDate`, `endDate`, `scheduleState`, `actualStartDate`, `actualEndDate`, `verifiedOn`, `updatedAt`, `statusDate`, `stale` (plus `match` under `textContains`) — never `description`, `links`, `verificationSource` or `assigneeUserIds` — to locate a card cheaply before `GET /api/cards/{cardId}`. `statusDate` is the dated STATO (or AGGIORNATO) line read from the description's labelled layout, null when neither carries a date; `stale` is true when that date is more than 14 days old. `includeDeleted=true` is exclusive trash: only cards with `deletedAt` set, `listId` may be null.","parameters":[{"name":"titleContains","in":"query","required":false,"description":"Case-insensitive substring filter on card title (server-side ILIKE, wildcard-escaped).","schema":{"type":"string","minLength":1,"maxLength":200}},{"name":"textContains","in":"query","required":false,"description":"Case-insensitive substring filter on title, description, comment bodies, checklist items and subtask titles; several words mean every word, each anywhere on the card. Requires view=summary; adds match: { field, snippet } to a returned summary when the hit is locatable.","schema":{"type":"string","minLength":2,"maxLength":100}},{"name":"updatedSince","in":"query","required":false,"description":"ISO datetime; only cards updated at or after it.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z))$"}},{"name":"citing","in":"query","required":false,"description":"A cardKey; only cards whose citation graph points at it. A key on a board the caller cannot read answers the empty result, like a key that names no card.","schema":{"type":"string","pattern":"^[A-Z0-9]{2,8}-(0|[1-9]\\d*)$"}},{"name":"view","in":"query","required":false,"description":"'full' (default) returns every field; 'summary' returns the cheap projection (id, cardKey, title, listId, startDate, endDate, scheduleState, actualStartDate, actualEndDate, verifiedOn, updatedAt, statusDate, stale); 'lint' returns only cards with findings as CardLint rows.","schema":{"type":"string","enum":["full","summary","lint"]}},{"name":"includeDeleted","in":"query","required":false,"description":"Exclusive trash listing: only cards with deletedAt set. listId may be null. Unlike includeArchived on boards, this is not additive. Default false.","schema":{"type":"boolean"}}]},"post":{"operationId":"createCard","summary":"Create a card with optional inline checklist","tags":["Cards"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Card"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Pass `ifSimilar: 'reject'` to be refused with 409 CONFLICT and `details: { similar: [{ cardKey, title, similarity }] }` — the titles on the workspace's boards you can read with trigram similarity >= 0.5, at most five, best first; a private board you are not a member of is never consulted — instead of creating a near-duplicate. Default is 'create'. A `description` over the 2000-character cap answers 400 VALIDATION_ERROR with `details: { rule: 'index-card', limit: 2000, hint }` — the hint names the index-card split of card-authoring.md; the validation message itself carries the same hint, which is also what MCP callers receive, in the same envelope, since the server validates tool inputs itself (2026-09-11). `kind: 'guidance'` cannot be set at creation by a Bearer token, grant or not (403 FORBIDDEN, `details.reason: 'no_consent_path'`): create the card, then promote it with updateCard under a guidance write grant with `confirm: 'guidance'` and `expectedUpdatedAt`; a workspace owner or admin sets it from the web app directly.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/cards/{cardId}":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"get":{"operationId":"getCard","summary":"Get a card from a readable board","tags":["Cards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardDetail"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"The only operation that returns `CardDetail`: the card plus its ordered `subtasks` (dated sub-work), `seq` (the card's last retained event seq, 0 when none — pass it back as `expectedSeq` on updateCard), and `cites` (the cards it cites) and `citedBy` (the cards citing it), each `{ card, title }` where `card` is a cardKey, capped at 50 and ordered by cardKey — `citedBy` with the `digest` cards after every other kind, and `citedByDigests` counting the digests citing the card, those past the cap included (since 2026-10-16). Citations are read from the description, every comment and every checklist item; a card named before it exists is linked when it is created. Both citation lists are filtered to boards the caller can read, so a neighbour on a private board appears in neither — its key and title are absent entirely, not redacted. That filter is archived-inclusive while this route's own gate is not, so a listed key is usually, not always, spendable here: a neighbour on an ARCHIVED board answers 404 unless the caller is one of its explicit members."},"patch":{"operationId":"updateCard","summary":"Update card fields","tags":["Cards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardUpdated"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"412":{"description":"A stale `expectedUpdatedAt` or `expectedSeq`: details.currentUpdatedAt, details.currentSeq and details.events (missed events, oldest first, at most 20; eventsTruncated when there were more). expectedUpdatedAt is an exact string comparison; when it is stale on a call that sends `sections` alone, details.conflictingSections names the blocks that moved on, and a stale call that also sends any other field, even one restated unchanged, is refused whole and writes nothing. expectedSeq also covers comment, checklist-item and subtask writes and moves across lists, not reorders, a move within one list or an editor autosave inside its checkpoint window.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Pass `expectedUpdatedAt` (the `updatedAt` you read) to refuse the write with 412 when someone changed the card in between, instead of silently replacing their work. Or pass `expectedSeq` (the card's `seq` from getCard, exclusive with `expectedUpdatedAt`) to also cover comment, checklist-item and subtask writes and moves across lists — not reorders, a move within one list, or an editor autosave inside its checkpoint window, which append no event (pass `expectedUpdatedAt` when a human may be typing in the card). A call that changes nothing — every field restated as the card holds it, assignees merely reordered — writes nothing: no event, no `Tre-Event-Seq`, and `updatedAt` stays, so the `expectedUpdatedAt` you hold remains valid; anything that does change moves `updatedAt`, a reorder of `links` included (reported as `changes.links.reordered`). A 412 carries `details.currentSeq` and `details.events` (missed events, oldest first, at most 20; `eventsTruncated` when there were more). While a subtask holds a planned date, the card's plan can be widened but neither cleared nor narrowed under it: the refusal (`400`, `details.rule` `CARD_HAS_NO_DATES` or `SUBTASK_OUT_OF_RANGE`) names the blocking subtask and the narrowest plan that would do — Tre never widens the card for you. A `description` over the 2000-character cap answers 400 VALIDATION_ERROR with `details: { rule: 'index-card', limit: 2000, hint }` and the same hint in the validation message (see createCard). To rewrite one block and leave the rest exactly as it is, send `sections` instead of `description`: `{ STATUS: { date: 'YYYY-MM-DD', text }, NEXT_STEP, PURPOSE, OTHER }` (or STATO / PROSSIMO_PASSO / SCOPO / ALTRO; null clears a block; both together answer 400). A block's text ends at the next line that opens with an uppercase `LABEL:`: a paragraph such as `SOURCES: …` or `CONTEXT: …` belongs to OTHER and survives a write to the other three blocks (one the stored document had filed inside the block you rewrite is moved to the front of OTHER, and the event names `other` too); a write never touches a block it does not name. For the same reason the text you send for PURPOSE, STATUS or NEXT STEP cannot itself carry such a line below its first: 400 BAD_REQUEST with `details: { rule: 'block-text', block, line }` — send the block without it. To change or remove the paragraph, write OTHER, which is replaced whole. The server composes the description from the blocks; the STATUS/STATO it replaces goes to the description history (`GET /api/cards/{cardId}/history`) and leaves no comment. On reference, digest and guidance cards the dated block is written as UPDATED/AGGIORNATO whichever of STATUS/STATO/UPDATED/AGGIORNATO you send. The event names the blocks in `sections`. The composed description, labels and the blank lines between blocks included, must fit the 2000-character cap: past it the write answers 400 BAD_REQUEST with `details: { rule: 'index-card', block, limit: 2000 }` naming the longest block, so a text accepted on create can be refused on update — shorten it or move content to checklist items, comments or links. On a call that sends `sections` alone, a stale expectedUpdatedAt no longer refuses outright: the write applies when none of the blocks you name changed in between, and the answer carries `merged.sections` (the blocks others changed); a named block that moved on answers 412 with `details.conflictingSections`, so re-read that block only. A stale call that also sends any other field (a title, a kind, a date, links, assignees — even one restated unchanged) is refused whole with 412 and writes nothing: send the blocks in their own call. The workspace guidance card is gated: rewriting its `description`, setting `kind: 'guidance'` on a card, or changing the kind of the card that is guidance is for a workspace owner or admin from the web app — or for a Bearer token that owner or admin has allowed for the workspace (grantGuidanceWrite; Settings → API tokens → Allow guidance writes), which must then send `confirm: 'guidance'` AND `expectedUpdatedAt` in the same call. Without a live grant the answer is 403 FORBIDDEN with `details: { reason, grant: 'guidance-write', how }` (reason is no_grant, grant_expired, grant_revoked or not_workspace_admin; `no_consent_path` is the refusal of the consent-less paths — createCard with `kind: 'guidance'` and restoreCardHistoryVersion — never of this operation); with a grant but without the consent it is 400 BAD_REQUEST with `details: { missing: [...] }`; a stale `expectedUpdatedAt` is the 412 above. A granted write's `card.updated` event carries `guidance: { grantId, grantedBy, grantedAt, expiresAt }` beside its diff.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardUpdate"}}}}},"delete":{"operationId":"deleteCard","summary":"Move a card to the trash","tags":["Cards"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"The card, its cardKey, checklist, comments and description history stay for 30 days. Live reads answer 404. Restore with POST /api/cards/{cardId}/restore. A second delete is a no-op."}},"/api/cards/{cardId}/restore":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"post":{"operationId":"restoreCard","summary":"Restore a card from the trash","tags":["Cards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Card"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Returns the card to its original list if that list still exists, otherwise the leftmost list of the board, at the bottom. A second call on a live card is a no-op. `409 CONFLICT` means the lists the restore chose were deleted before it could write, 3 attempts in a row: the card is still in the trash, and the same call can be sent again."}},"/api/cards/{cardId}/move":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"post":{"operationId":"moveCard","summary":"Move a card within or across columns","tags":["Cards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Card"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"A move within the same column is presentation: no ledger event, no `Tre-Event-Seq`, `updatedAt` untouched. A move across columns appends `card.moved` (the header carries its seq) and still never bumps the card's `updatedAt`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardMove"}}}}}},"/api/cards/{cardId}/checklist":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"get":{"operationId":"listChecklist","summary":"List checklist items","tags":["Checklist"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"post":{"operationId":"createChecklistItem","summary":"Append a checklist item","tags":["Checklist"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistItem"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistItemCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/cards/{cardId}/checklist/reorder":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"post":{"operationId":"reorderChecklist","summary":"Reorder checklist items","tags":["Checklist"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistReorder"}}}}}},"/api/checklist-items/{itemId}":{"parameters":[{"name":"itemId","in":"path","required":true,"description":"Checklist item UUID.","schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateChecklistItem","summary":"Update a checklist item","tags":["Checklist"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistItem"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChecklistItemUpdate"}}}}},"delete":{"operationId":"deleteChecklistItem","summary":"Delete a checklist item","tags":["Checklist"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/cards/{cardId}/subtasks":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"get":{"operationId":"listSubtasks","summary":"List card subtasks","tags":["Subtasks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubtaskItemsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}},"post":{"operationId":"createSubtask","summary":"Create a dated subtask","tags":["Subtasks"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subtask"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires at least one of the four date fields (`startDate`, `endDate`, `actualStartDate`, `actualEndDate`); when both planned dates are set, `endDate` must be >= `startDate`. Planned dates need the card to carry both planned dates and must fall inside them — refused with 400 and `details.rule` `CARD_HAS_NO_DATES` or `SUBTASK_OUT_OF_RANGE`, naming the plan and the offending date; actual dates are independent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubtaskCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/cards/{cardId}/subtasks/reorder":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"post":{"operationId":"reorderSubtasks","summary":"Reorder card subtasks","tags":["Subtasks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubtaskItemsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubtaskReorder"}}}}}},"/api/subtasks/{subtaskId}":{"parameters":[{"name":"subtaskId","in":"path","required":true,"description":"Subtask UUID.","schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateSubtask","summary":"Update a subtask","tags":["Subtasks"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Subtask"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"When the body sets both `startDate` and `endDate`, `endDate` must be >= `startDate`. The merged planned dates must stay inside the card's plan, which must carry both planned dates (400, `details.rule` `CARD_HAS_NO_DATES` or `SUBTASK_OUT_OF_RANGE`, naming the plan and the offending date); actual dates are independent.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubtaskUpdate"}}}}},"delete":{"operationId":"deleteSubtask","summary":"Delete a subtask","tags":["Subtasks"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/cards/{cardId}/comments":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"get":{"operationId":"listCardComments","summary":"List card comments","tags":["Comments"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Same `since` contract as MCP `list_comments` (`commentListQuerySchema` in lib/schemas/comment.ts validates both). Omit `since` for the whole thread, oldest first. Pass it (an ISO 8601 datetime carrying a timezone — `Z` or `+02:00` — e.g. a comment's `createdAt` verbatim) to fetch only comments strictly newer than it — at the millisecond, the precision every response carries, so a cursor equal to a comment's `createdAt` never returns that comment again — still oldest first.","parameters":[{"name":"since","in":"query","required":false,"description":"ISO 8601 datetime WITH a timezone — `Z` or an extended numeric offset such as `+02:00`; a zone-less value (`2026-09-02T10:00:00`) or a bare date is refused with 400. Return only comments created strictly after this instant, oldest first. Omit for the whole thread.","schema":{"type":"string","format":"date-time","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"}},{"name":"limit","in":"query","required":false,"description":"At most this many comments — the newest ones, still oldest first (1–200). With `since`, the newest N newer than it, not the next N: when more arrived, the older ones in between are skipped, so page forward with `since` alone.","schema":{"type":"integer","minimum":1,"maximum":200}}]},"post":{"operationId":"createComment","summary":"Create a comment","tags":["Comments"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CardComment"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/comments/{commentId}":{"parameters":[{"name":"commentId","in":"path","required":true,"description":"Comment UUID.","schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateComment","summary":"Edit content or toggle comment resolution","tags":["Comments"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentUpdateResponse"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"The body must include exactly one of `resolved` or `content` — never both. `content` is the author's alone; a `system` comment (the server's record of a replaced STATO) refuses `content` with 403 for everyone, the attributed author included, while `resolved` stays allowed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CommentUpdate"}}}}},"delete":{"operationId":"deleteComment","summary":"Delete a comment","tags":["Comments"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"The author, or an owner or admin of the board's workspace for anyone's comment (both need editor access to the board). A `system` comment is only theirs to delete — its attributed author is refused with 403."}},"/api/cards/{cardId}/history":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}}],"get":{"operationId":"listCardHistory","summary":"List card description versions","tags":["History"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HistoryResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/cards/{cardId}/history/{versionId}":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID, or its stable cardKey (e.g. `DESIGN-42`) — accepted wherever the UUID is, on every card-scoped business route. The internal `yjs-state` endpoints stay UUID-only.","schema":{"type":"string","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}|[A-Z0-9]{2,8}-(0|[1-9][0-9]*))$"}},{"name":"versionId","in":"path","required":true,"description":"Card history version UUID.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getCardHistoryVersion","summary":"Get one card description version, as text and as raw state","tags":["History"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"`text` is the plain description text of this version — read this to verify what was overwritten. `state` is the raw base64 Yjs snapshot the editor uses to restore; it is not human-readable."},"post":{"operationId":"restoreCardHistoryVersion","summary":"Restore a card description snapshot","tags":["History"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessResponse"}}},"headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"A whole-text write like PATCH: archives the current description first, an empty one included (as an empty version), then overwrites it with the snapshot. Restoring the text the card already shows is a no-op: no version, no event, no `Tre-Event-Seq`. On the workspace guidance card a Bearer token answers 403 FORBIDDEN with `details.reason: 'no_consent_path'` whatever guidance write grant it holds: restore it from the web app, or send the text through updateCard under a grant."}},"/api/cards/{cardId}/yjs-state":{"parameters":[{"name":"cardId","in":"path","required":true,"description":"Card UUID. This route does not accept a cardKey.","schema":{"type":"string","format":"uuid"}}],"get":{"operationId":"getCardYjsState","summary":"Get the internal CRDT state","tags":["Internal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/YjsStateResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"x-tre-internal":true},"put":{"operationId":"updateCardYjsState","summary":"Persist the internal CRDT state","tags":["Internal"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content","headers":{"Tre-Event-Seq":{"$ref":"#/components/headers/TreEventSeq"}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/YjsStateUpdate"}}}},"x-tre-internal":true}},"/api/realtime/token":{"post":{"operationId":"createRealtimeToken","summary":"Mint a short-lived realtime access token for a board","tags":["Internal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelayTokenResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Transport plumbing for Tre’s own clients: authorizes a WebSocket to one board with the caller’s board role. PATs require write or admin scope after board visibility. A finite parent caps the child token’s nominal expiry at its own expiry or 15 minutes; existing verifier leeway and socket retirement behavior remain unchanged.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RelayTokenRequest"}}}},"x-tre-internal":true}},"/api/timeline":{"get":{"operationId":"getTimeline","summary":"Get dated cards and subtasks across visible boards","tags":["Timeline"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TimelinePayload"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"`start` must be <= `end`.","parameters":[{"name":"workspace","in":"query","required":false,"description":"Workspace slug. Omit to span every workspace visible to the caller; a workspace-bound token sees only its audience.","schema":{"type":"string"}},{"name":"start","in":"query","required":true,"description":"Inclusive ISO date YYYY-MM-DD.","schema":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"}},{"name":"end","in":"query","required":true,"description":"Inclusive ISO date YYYY-MM-DD.","schema":{"type":"string","format":"date","pattern":"^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"}},{"name":"boards","in":"query","required":false,"description":"Comma-separated board UUIDs.","style":"form","explode":false,"schema":{"default":[],"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}}},{"name":"assignees","in":"query","required":false,"description":"Comma-separated assignee UUIDs.","style":"form","explode":false,"schema":{"default":[],"type":"array","items":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}}},{"name":"withSubtasksOnly","in":"query","required":false,"description":"Only cards with subtasks.","schema":{"default":false,"type":"boolean"}},{"name":"dateBasis","in":"query","required":false,"description":"schedule (default), actual or both. Dates retain their meaning; actual-only cards may have null schedule dates.","schema":{"default":"schedule","type":"string","enum":["schedule","actual","both"]}},{"name":"includeInactive","in":"query","required":false,"description":"Include suspended/cancelled schedules (default true). Actual observations remain visible in actual/both mode.","schema":{"default":true,"type":"boolean"}}]}},"/api/catch-up":{"get":{"operationId":"catchUp","summary":"Catch up on the events ledger: the cold-start brief, or a delta since a cursor","tags":["Events"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CatchUpResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"410":{"description":"Cursor damaged or forged; call again without one","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Same contract as MCP's `catch_up` (`catchUpQuerySchema` in lib/schemas/events.ts validates both). Without `cursor`: the brief — the NON-ARCHIVED boards you can read (each with its id) with their lists (with their ids) and card counts, a tail of recent activity (`recent` is a taste of the ledger, not a page — no `hasMore` — and, unlike the inventory, it does include archived boards), per workspace the care counts `stale`, `inventory` and `attention` (`BriefWorkspace` says what each counts), and a fresh `cursor`. With `cursor`: `{ events, cursor, hasMore, resynced? }`, only what happened since. Activity on boards you cannot read is filtered out after the scan, so a page may carry fewer events than `limit` — even none — while `hasMore` is true: keep calling with the returned cursor until `hasMore` is false. Keep the cursor verbatim between sessions, like a cardKey; never parse it. `limit` (1-100, default 50) is ignored without a cursor and split evenly across the workspaces in scope (floor, minimum one each — with more workspaces than `limit`, a page can carry one event per workspace and exceed it). A position retention has pruned past is restarted from the oldest event that workspace still has and reported in `resynced` (the delta's optional array of slugs) — not an error, and the other workspaces' deltas in the same response are unaffected. Only a cursor that is damaged or names a position this ledger never issued answers 410 `STALE_CURSOR`: call again without one to restart from the brief.","parameters":[{"name":"workspace","in":"query","required":false,"description":"Workspace slug. Omit to span every workspace visible to the caller; a workspace-bound token sees only its audience.","schema":{"type":"string","minLength":1,"maxLength":60,"pattern":"^[a-z0-9-]+$"}},{"name":"cursor","in":"query","required":false,"description":"The cursor a previous call returned, 1-2048 characters. OMIT the parameter entirely to get the brief instead of a delta: sending it empty (`?cursor=`) is a 400, not a brief.","schema":{"type":"string","minLength":1,"maxLength":2048}},{"name":"limit","in":"query","required":false,"description":"Maximum events in a delta page (1-100, default 50). Ignored without a cursor. Split evenly across the workspaces in scope (floor, minimum one each), so a caller in more workspaces than `limit` gets one event per workspace and can exceed it.","schema":{"type":"integer","minimum":1,"maximum":100}}]}},"/api/me":{"get":{"operationId":"getMe","summary":"Get the caller's own identity and workspaces","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Same body as MCP's `whoami`: id, name, email, avatar, and the workspaces visible to the caller with the role held in each. A workspace-bound token sees only its audience. Bearer callers also receive token (name, kind, scope, workspace, expiresAt); sessions omit it. Use `id` for `assigneeUserIds` and a workspace `slug` for the `?workspace=` parameter elsewhere — the only way to learn either without triggering a write error."},"delete":{"operationId":"deleteMe","summary":"Delete the calling account (GDPR erasure); confirmEmail must match","tags":["Users"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"Account deletion requires the web session; Bearer tokens cannot delete accounts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires the authenticated web session; every Bearer token, including admin scope, receives 403 FORBIDDEN (Account deletion requires the web session). Irreversible. Refused with 409 while the caller is the only owner of a workspace that still has other members — transfer ownership or delete those workspaces first. A second, rarer 409 (`Workspace memberships changed while deleting — try again`) means a workspace membership changed while the deletion ran: no account or workspace was deleted, and the same call can be sent again. Sole-member workspaces are deleted along with the account. confirmEmail must be sent as a JSON body.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountDeleteConfirm"}}}}}},"/api/me/export":{"get":{"operationId":"exportMyData","summary":"Export the caller's own data as JSON (GDPR portability)","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccountExport"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/me/connected-apps":{"get":{"operationId":"listConnectedApps","summary":"List OAuth grants the caller has authorized (Connected apps)","tags":["Tokens"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectedAppsResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"Connected apps require the web session; Bearer tokens cannot list grants","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires the authenticated web session; every Bearer token, including admin scope, receives 403 FORBIDDEN (Connected apps require the web session), and OAuth access tokens 401. Each app is one live grant: client name, workspace, scope, and last use (lastUsedAt is the last token mint — the code exchange or a refresh — not the last MCP call)."}},"/api/me/connected-apps/{grantId}":{"parameters":[{"name":"grantId","in":"path","required":true,"description":"OAuth grant UUID (Connected apps).","schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"revokeConnectedApp","summary":"Revoke an OAuth grant (Connected apps)","tags":["Tokens"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"Connected apps require the web session; Bearer tokens cannot revoke grants","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires the authenticated web session; every Bearer token, including admin scope, receives 403 FORBIDDEN (Connected apps require the web session). Revokes the grant, every access token it issued, and consumes its refresh tokens. Another users grant answers 404."}},"/api/users":{"get":{"operationId":"listAssignableUsers","summary":"List users visible for assignment","tags":["Users"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsersResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"parameters":[{"name":"workspace","in":"query","required":false,"description":"Workspace slug. Omit to span every workspace visible to the caller; a workspace-bound token sees only its audience.","schema":{"type":"string"}},{"name":"boardId","in":"query","required":false,"description":"Scope to members of one readable board.","schema":{"type":"string","format":"uuid"}}]}},"/api/tokens":{"get":{"operationId":"listTokens","summary":"List caller personal API tokens","tags":["Tokens"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokensResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Personal tokens only (kind personal); OAuth access tokens belong to their grant and are listed under Connected apps instead. A workspace-bound caller sees only its own tokens bound to that same workspace; unbound and differently bound tokens are excluded. Each token carries its guidanceGrants — the non-revoked guidance write grants on it, active or expired, newest first (grantGuidanceWrite)."},"post":{"operationId":"createToken","summary":"Create a personal API token; plaintext is returned once","tags":["Tokens"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenCreationResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires admin token scope or the web session. Read and write tokens receive 403 FORBIDDEN. Optional workspace (slug), scope (read/write/admin, default admin), and future expiresAt limit the token. Sessions and unlimited parents default to every workspace and no expiry. Omitted audience/expiry inherit finite parent limits; inherited audience still requires current membership. An unknown or outside workspace answers 404 NOT_FOUND (Workspace not found); expiry later than the parent answers 403 FORBIDDEN. Idempotency fingerprints include effective resolved limits: a cached broader token cannot be replayed under narrower limits (422 IDEMPOTENCY_KEY_REUSED).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TokenCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/tokens/{tokenId}":{"parameters":[{"name":"tokenId","in":"path","required":true,"description":"Personal API token UUID.","schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"revokeToken","summary":"Revoke a personal API token","tags":["Tokens"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires admin token scope or the web session. Read and write tokens receive 403 FORBIDDEN. Personal tokens only: the id of an OAuth access token answers 404 NOT_FOUND (Token not found) — revoke the grant from Connected apps instead. A workspace-bound caller can revoke only its own tokens bound to the same workspace; other token ids answer 404 NOT_FOUND (Token not found)."}},"/api/tokens/{tokenId}/guidance-grant":{"parameters":[{"name":"tokenId","in":"path","required":true,"description":"Personal API token UUID.","schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"grantGuidanceWrite","summary":"Allow one of your personal tokens to write the workspace guidance card, for a while","tags":["Tokens"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidanceWriteGrant"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"Guidance write grants require the web session, or the caller is not an owner or admin of the workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires the authenticated web session; every Bearer token, including admin scope, receives 403 FORBIDDEN (Guidance write grants require the web session). The caller must be an owner or admin of `workspace` (403 otherwise; a slug that is not the caller's answers 404 NOT_FOUND) and `tokenId` must be one of their own live personal tokens (404 NOT_FOUND otherwise); a workspace-bound token can only be allowed for its own workspace (400). The grant lasts `durationMinutes` (default 60, at most 1440) and supersedes any open grant on the same token and workspace. It never replaces the owner/admin role the token's person must still hold at write time, and the granted write itself must carry `confirm: 'guidance'` and `expectedUpdatedAt` (see updateCard). Every granted write is recorded on the events ledger with the grant and the person who allowed it.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GuidanceGrantCreate"}}}}},"delete":{"operationId":"revokeGuidanceWriteGrant","summary":"Stop allowing a personal token to write the guidance card","tags":["Tokens"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"Guidance write grants require the web session; Bearer tokens cannot revoke them","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires the authenticated web session; every Bearer token, including admin scope, receives 403 FORBIDDEN (Guidance write grants require the web session). Closes every open guidance write grant of the caller's own token, whatever workspace each names; another person's token answers 404 NOT_FOUND (Token not found). Idempotent: a token with nothing open still answers 204."}},"/api/health":{"get":{"operationId":"getHealth","summary":"Whether the application is up and its database answers","tags":["Public"],"security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthReport"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Public: no session and no bearer; what an uptime monitor asks. `200 { status: \"ok\", db: \"ok\", commit }` when one database round-trip succeeds within three seconds — `commit` is the build the deployment runs, null outside a platform build. `503 SERVICE_UNAVAILABLE` (Database unreachable) with Retry-After when it does not; the same 503 when the rate limiter is unavailable, because every other route is refusing for that reason too. Never cached. 120 requests a minute per network address.","x-tre-internal":true}},"/api/workspaces":{"post":{"operationId":"createWorkspace","summary":"Create a workspace; the caller becomes its owner","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceCreated"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Requires unbound admin token scope or the web session. Read and write tokens receive 403 FORBIDDEN. Every workspace-bound token receives 403 FORBIDDEN (Workspace-bound tokens cannot create workspaces), before writes or idempotency replay. On a billing-enabled installation the first workspace a person creates starts their one 14-day trial; a workspace created after that is read-only until a plan is chosen. A self-hosted installation has neither.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceCreate"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/workspaces/{slug}":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}}],"patch":{"operationId":"updateWorkspace","summary":"Rename the workspace (admin) and/or change its slug (owner)","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Changing the slug changes every URL under /w/{slug}; old links stop resolving.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceUpdate"}}}}},"delete":{"operationId":"deleteWorkspace","summary":"Permanently delete the workspace and everything in it (owner only)","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"confirmSlug must equal the workspace slug. Cancels the Stripe subscription first when one exists. Irreversible.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceDeleteConfirm"}}}}}},"/api/workspaces/{slug}/owner":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}}],"post":{"operationId":"transferWorkspaceOwnership","summary":"Transfer ownership to another member (owner only); the caller becomes admin","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OwnerTransfer"}}}}}},"/api/workspaces/{slug}/people":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}}],"get":{"operationId":"listWorkspacePeople","summary":"List the members and pending invitations of a workspace (any member; any token scope)","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacePeopleResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/workspaces/{slug}/cards":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}}],"get":{"operationId":"searchWorkspaceCards","summary":"Search the cards of a workspace by a word (any member; any token scope)","tags":["Cards"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceCardSearchResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"The REST twin of MCP `list_cards` with `workspace` in place of `boardId` (design record 2026-09-25-workspace-lexical-search-design): one query over every non-archived board the caller can read in the workspace — public boards plus the private ones they are a member of — never a fan-out. Requires `textContains` and `view=summary`, and nothing else: the per-board filters (`titleContains`, `updatedSince`, `citing`, `includeDeleted`) are refused beside the workspace address by name, 400 VALIDATION_ERROR, exactly as MCP refuses them (the shared `workspaceCardListQuerySchema` in lib/schemas/card.ts). Answers `{ cards, truncated }`: the `CardSummary` rows of the per-board search — `match: { field, snippet }` included, same fields, same precedence, same snippet — each with `boardId` and `board` (the board's slug), ranked by the field that holds every word of the search — title, then an `ALIASES:` line, the description, a comment, a checklist item, a subtask title, and last the cards whose words are spread over several fields — most recently updated first within a rank, at most 50, so the cap keeps the best hits (since 2026-10-16; before, time alone). `truncated: true` means more matched than the cap lists (add a word); `truncated: false` is a statement of absence: no other live card on the boards you can read carries every word. Archived boards are out of a search as they are out of a listing. A slug the caller does not belong to, and any slug but its audience for a workspace-bound token, answers 404 NOT_FOUND like an unknown one.","parameters":[{"name":"textContains","in":"query","required":true,"description":"The word to find, case-insensitively, anywhere on a card: title, description, comment bodies, checklist items or subtask titles (2 to 100 characters, trimmed). Several words mean every word, each anywhere on the card: `fattura cliente` finds the card titled \"Fattura 12\" whose comment says \"al cliente\" (since 2026-10-16). Required: without it the workspace address is refused.","schema":{"type":"string","minLength":2,"maxLength":100}},{"name":"view","in":"query","required":true,"description":"Must be summary: a search answers the summary projection plus match, and no other view. Required, as it is beside textContains on the per-board route.","schema":{"type":"string","enum":["summary"]}}]}},"/api/workspaces/{slug}/invitations":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}}],"post":{"operationId":"inviteToWorkspace","summary":"Invite an email into a workspace (workspace admin role and admin token scope)","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceInvitationCreated"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceInvite"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/api/workspaces/{slug}/invitations/{email}":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}},{"name":"email","in":"path","required":true,"description":"URL-encoded email address.","schema":{"type":"string"}}],"delete":{"operationId":"revokeWorkspaceInvitation","summary":"Withdraw a pending invitation (workspace admin only)","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}}}},"/api/workspaces/{slug}/members/{userId}":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}},{"name":"userId","in":"path","required":true,"description":"User UUID.","schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"updateWorkspaceMemberRole","summary":"Change a workspace member role (workspace admin only)","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceMemberUpdate"}}}}},"delete":{"operationId":"removeWorkspaceMember","summary":"Remove a member from a workspace (workspace admin only)","tags":["Workspaces"],"security":[{"bearerAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Their board memberships inside the workspace go too, and their OAuth grants and API tokens bound to it are revoked. If it was the person's last workspace, their sessions and every grant and token they hold are revoked."}},"/api/access-requests":{"post":{"operationId":"requestAccess","summary":"Ask for access to the private beta, for yourself or for the person you work for","tags":["Public"],"security":[],"responses":{"202":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessRequestReceipt"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Public: no session and no bearer. Body: `email` (required), `agents` (which of claude-code, codex, cursor, openclaw, chatgpt, other the person runs), `note` (up to 280 characters). Always answers `202 { status: \"received\" }` for a valid body, whether or not the address was already known — the endpoint never reveals membership. Five requests an hour per network address; a 429 carries Retry-After. Answers `404` on an installation that is not running a beta (`PUBLIC_ACCESS` other than `beta`).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessRequestInput"}}}}}},"/api/workspaces/{slug}/billing/checkout":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}}],"post":{"operationId":"createBillingCheckoutSession","summary":"Start a hosted Stripe Checkout session for this workspace","tags":["Internal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSessionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"UI plumbing for the billing settings page, not an agent surface. Workspace admins only. 404s when billing is not configured on this installation (self-host). 403 (`This workspace is suspended and read-only`, followed by the support address) while the operator has suspended the workspace; the billing portal stays open. 409 when the workspace already has an active or past-due subscription: the plan is changed from the portal.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingCheckout"}}}},"x-tre-internal":true}},"/api/workspaces/{slug}/billing/portal":{"parameters":[{"name":"slug","in":"path","required":true,"description":"Workspace slug, as it appears in the URL.","schema":{"type":"string"}}],"post":{"operationId":"createBillingPortalSession","summary":"Open the Stripe customer portal for this workspace's billing","tags":["Internal"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingSessionResponse"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"UI plumbing for the billing settings page, not an agent surface. Workspace admins only. 404s when billing is not configured on this installation (self-host), or when the workspace has no billing account yet.","x-tre-internal":true}},"/api/webhooks/stripe":{"post":{"operationId":"receiveStripeWebhook","summary":"Stripe webhook receiver — the single writer of billing state after checkout","tags":["Internal"],"security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookReceipt"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Called by Stripe, not a person or agent: authenticated by the `stripe-signature` header (an HMAC over the raw body, verified against `STRIPE_WEBHOOK_SECRET`) rather than a Tre bearer token or web session. 404s when billing is not configured on this installation (self-host); 503 when the installation has a Stripe key but no webhook secret configured yet.","parameters":[{"name":"stripe-signature","in":"header","required":true,"description":"HMAC-SHA256 signature Stripe computes over the raw request body and a timestamp; the entire authentication for this route.","schema":{"type":"string"}}],"x-tre-internal":true}},"/api/ops/access-requests/{requestId}":{"parameters":[{"name":"requestId","in":"path","required":true,"description":"Access request UUID.","schema":{"type":"string","format":"uuid"}}],"patch":{"operationId":"setAccessRequestStatus","summary":"Operator: mark a beta access request invited, declined, or new again","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. Bookkeeping only: Tre has no sign-in gate, so a status admits and refuses nobody. Moving between invited and declined needs a reopen first (409).","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessRequestStatusUpdate"}}}},"x-tre-internal":true},"delete":{"operationId":"deleteAccessRequest","summary":"Operator: delete a beta access request","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. Removes the row: the address, the agents and the note.","x-tre-internal":true}},"/api/ops/proposals/{proposalId}/approve":{"parameters":[{"name":"proposalId","in":"path","required":true,"description":"Operator proposal UUID.","schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"approveOperatorProposal","summary":"Operator: approve an agent’s proposal","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The proposal is not open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. Runs the act the proposal names — the same service the console runs by hand — as this operator; the operator log row says it came from a proposal and names it. 404 for a proposal that does not exist; 409 when it is already decided or expired, its target no longer exists, or its act has nothing left to do on the target as it is now (`Nothing left to do: …`; the proposal stays open); 400 when the target changed after the proposal and `acknowledgeStale` is not true, or when the proposal suspends a workspace and `confirmSlug` does not give the workspace’s slug. It may give a reference: a ticket or card key, never an address.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsProposalApprove"}}}},"x-tre-internal":true}},"/api/ops/proposals/{proposalId}/reject":{"parameters":[{"name":"proposalId","in":"path","required":true,"description":"Operator proposal UUID.","schema":{"type":"string","format":"uuid"}}],"post":{"operationId":"rejectOperatorProposal","summary":"Operator: reject an agent’s proposal","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"description":"The proposal is not open","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. Writes the proposal alone: nothing it names is done. The body may give a note, up to 500 characters. 404 for a proposal that does not exist; 409 when it is already decided or expired.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsProposalReject"}}}},"x-tre-internal":true}},"/api/ops/users/{userId}/tokens/{tokenId}":{"parameters":[{"name":"userId","in":"path","required":true,"description":"User UUID.","schema":{"type":"string","format":"uuid"}},{"name":"tokenId","in":"path","required":true,"description":"Personal API token UUID.","schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"revokeUserToken","summary":"Operator: revoke one personal token of a person","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. Calls made with the token answer 401 from now on. Tre does not notify its owner. The body gives the reason, from a closed list, and may give a reference: a ticket or card key, never an address. A token that is not this person’s, is not a personal token or is already revoked answers 404.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsCredentialRevoke"}}}},"x-tre-internal":true}},"/api/ops/users/{userId}/grants/{grantId}":{"parameters":[{"name":"userId","in":"path","required":true,"description":"User UUID.","schema":{"type":"string","format":"uuid"}},{"name":"grantId","in":"path","required":true,"description":"OAuth grant UUID (Connected apps).","schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"revokeUserGrant","summary":"Operator: disconnect one connected app of a person","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. Revokes the grant, every access token it issued and its refresh tokens. The body gives the reason, from a closed list, and may give a reference: a ticket or card key, never an address. A grant that is not this person’s or is already revoked answers 404.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsCredentialRevoke"}}}},"x-tre-internal":true}},"/api/ops/users/{userId}/sessions":{"parameters":[{"name":"userId","in":"path","required":true,"description":"User UUID.","schema":{"type":"string","format":"uuid"}}],"delete":{"operationId":"revokeUserSessions","summary":"Operator: sign a person out of every browser","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. Deletes every web session of the person; a connected app keeps working until its grant is revoked. The body gives the reason, from a closed list, and may give a reference: a ticket or card key, never an address. A person who does not exist answers 404.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsCredentialRevoke"}}}},"x-tre-internal":true}},"/api/ops/workspaces/{workspaceId}/suspension":{"parameters":[{"name":"workspaceId","in":"path","required":true,"description":"Workspace UUID.","schema":{"type":"string","format":"uuid"}}],"put":{"operationId":"suspendWorkspace","summary":"Operator: suspend a workspace","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. Every board role in the workspace reads as viewer and new checkouts are refused; reading, export, people, the billing portal and deletion stay open. Billing is not touched. 409 when already suspended. The body gives the reason, from a closed list; `noticeSentOn`, the day the owner was written to — between 90 days before today and the day after it in UTC (400 otherwise) — or null when there was no prior notice; and `confirmSlug`, the workspace’s slug (400 when it is another). It may give `reviewOn`, the day to look at the suspension again — it lifts nothing — between today and 90 days ahead in UTC (400 otherwise), 14 days ahead when omitted; and a reference: a ticket or card key, never an address.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceSuspend"}}}},"x-tre-internal":true},"delete":{"operationId":"liftWorkspaceSuspension","summary":"Operator: lift the suspension of a workspace","tags":["Operator"],"security":[{"secureSessionAuth":[]},{"sessionAuth":[]}],"responses":{"204":{"description":"No content"},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"description":"The request did not come from the application’s own origin","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"404":{"description":"Not the operator, or no such object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"}}}},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"Operator console only: requires the web session of an address in the operator allowlist of this installation, sent from the application itself. Every other signed-in caller and every valid Bearer token receives 404 NOT_FOUND, whether or not this installation has an operator configured; a caller with no valid credential receives 401, as on every route. Recorded in the operator log. The workspace is writable again, unless its billing state makes it read-only too. Billing is not touched. The body is a JSON object, empty at least, and may give a reference: a ticket or card key, never an address. A workspace that is not suspended answers 404.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceSuspensionLift"}}}},"x-tre-internal":true}},"/api/operator/overview":{"get":{"operationId":"operatorOverview","summary":"Operator agent: the strip, the \"Needs you\" queue and the open proposals","tags":["Operator agent"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsAgentOverview"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"For the operator's agent credential (a personal token flagged by the installation's operator, see cloud/docs/ops-contract.md); every other caller receives 404 NOT_FOUND. Which Stripe and which access mode this installation runs, how many proposals wait, every attention line (the app's kind, its level, how many it counts, the ids behind it and the console page that lists them) and the open proposals, newest first. Read this first."}},"/api/operator/list":{"get":{"operationId":"operatorList","summary":"Operator agent: one view of the console","tags":["Operator agent"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsAgentList"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"For the operator's agent credential (a personal token flagged by the installation's operator, see cloud/docs/ops-contract.md); every other caller receives 404 NOT_FOUND. `view` is `people`, `accounts` (the workspaces), `requests` or `proposals`; `lens` is one of that view's lenses (400 naming them when it is another; the first is the default); `q` keeps the rows with a text cell that contains it, in any case. At most 200 rows; `total` counts the lens, or the rows kept when `q` is given.","parameters":[{"name":"view","in":"query","required":true,"description":"The view of the console.","schema":{"type":"string","enum":["people","accounts","requests","proposals"]}},{"name":"lens","in":"query","required":false,"description":"A lens of that view; the view's first when omitted.","schema":{"type":"string"}},{"name":"q","in":"query","required":false,"description":"Case-insensitive text filter over the rows’ text cells.","schema":{"type":"string","maxLength":200}}]}},"/api/operator/get":{"get":{"operationId":"operatorGet","summary":"Operator agent: one person, account, request or proposal","tags":["Operator agent"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsAgentGet"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"For the operator's agent credential (a personal token flagged by the installation's operator, see cloud/docs/ops-contract.md); every other caller receives 404 NOT_FOUND. The detail page as an object. `kind` is one of `person`, `account`, `request`, `proposal`. For an account, `accessNow` says in a sentence whether it can write and why. `proposals` are the open ones about the object and `log` is its operator log (empty for a request and a proposal). 404 for an object that does not exist.","parameters":[{"name":"kind","in":"query","required":true,"description":"What kind of object.","schema":{"type":"string","enum":["person","account","request","proposal"]}},{"name":"id","in":"query","required":true,"description":"The object’s UUID.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}}]}},"/api/operator/log":{"get":{"operationId":"operatorLog","summary":"Operator agent: the operator log","tags":["Operator agent"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsAgentLog"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"For the operator's agent credential (a personal token flagged by the installation's operator, see cloud/docs/ops-contract.md); every other caller receives 404 NOT_FOUND. The last operator acts, newest first, at most 200; narrow by `accountId` or `subjectUserId`. A row names who acted, what, when, why and, when the act ran from a proposal, which one and who proposed it.","parameters":[{"name":"accountId","in":"query","required":false,"description":"Only the acts on this workspace.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},{"name":"subjectUserId","in":"query","required":false,"description":"Only the acts on this person.","schema":{"type":"string","format":"uuid","pattern":"^([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12})$"}},{"name":"limit","in":"query","required":false,"description":"How many rows at most; the cap when omitted.","schema":{"default":200,"type":"integer","minimum":1,"maximum":200}}]}},"/api/operator/proposals":{"post":{"operationId":"proposeOperatorAction","summary":"Operator agent: ask the operator to run one of the console’s acts","tags":["Operator agent"],"security":[{"bearerAuth":[]}],"responses":{"201":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsAgentProposeResult"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthenticated"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"422":{"$ref":"#/components/responses/IdempotencyKeyReused"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"},"503":{"$ref":"#/components/responses/ServiceUnavailable"}},"description":"For the operator's agent credential (a personal token flagged by the installation's operator, see cloud/docs/ops-contract.md); every other caller receives 404 NOT_FOUND. Writes a proposal and nothing else: the operator approves or rejects it at the console (`consoleUrl`), and only an approval runs the act. One open proposal per act and target: a repeat supersedes the earlier one (`supersededId`). 400 for a body the act does not take, a missing target id, or an act that cannot apply to the target as it is (a credential already revoked, a request already past `new` or already `new`, a person with no live session, a workspace already in or out of suspension, a suspension date the act would refuse), naming the reason; 404 for a target that does not exist. Accepts `Idempotency-Key`.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpsPropose"}}}},"parameters":[{"name":"Idempotency-Key","in":"header","required":false,"description":"Opaque 1–200 character key. The same user, endpoint, and key replay the cached response for 24 hours when the request body fingerprint matches. A reused key with a different body answers 422 IDEMPOTENCY_KEY_REUSED; the same key while the original is still in flight answers 409 CONFLICT.","schema":{"type":"string","minLength":1,"maxLength":200}}]}},"/.well-known/oauth-protected-resource":{"get":{"operationId":"getProtectedResourceMetadata","summary":"OAuth protected-resource metadata for the MCP surface (RFC 9728)","tags":["OAuth"],"security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthProtectedResourceMetadata"}}}},"404":{"description":"OAuth door is off (`OAUTH_ENABLED` unset or not `true`)."}},"description":"Published when `OAUTH_ENABLED=true`. Answers 404 while the flag is off. No Tre bearer — connectors discover the authorization server from a 401 challenge on `/api/mcp`.","x-tre-internal":true}},"/.well-known/oauth-authorization-server":{"get":{"operationId":"getAuthorizationServerMetadata","summary":"OAuth 2.1 authorization-server metadata (RFC 8414)","tags":["OAuth"],"security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthAuthorizationServerMetadata"}}}},"404":{"description":"OAuth door is off (`OAUTH_ENABLED` unset or not `true`)."}},"description":"Published when `OAUTH_ENABLED=true`. Answers 404 while the flag is off. No Tre bearer. Advertises authorize, token and revoke endpoints, S256 PKCE, and `none` / `private_key_jwt` client auth.","x-tre-internal":true}},"/oauth/authorize":{"get":{"operationId":"oauthAuthorize","summary":"OAuth 2.1 authorization endpoint (browser redirect flow)","description":"Browser-only. Requires the authenticated web session (a Bearer token is not a person). Validates the CIMD client and exact redirect, then redirects to consent; after consent redirects to the client with `code`, `state` and `iss`. Answers 404 while `OAUTH_ENABLED` is off. No Tre bearer.","tags":["OAuth"],"security":[],"x-tre-internal":true,"parameters":[{"name":"response_type","in":"query","required":true,"description":"Always `code`.","schema":{"type":"string","const":"code"}},{"name":"client_id","in":"query","required":true,"description":"HTTPS Client ID Metadata Document URL.","schema":{"type":"string","format":"uri"}},{"name":"redirect_uri","in":"query","required":true,"description":"HTTPS redirect URI; must equal one the client metadata document lists.","schema":{"type":"string","format":"uri"}},{"name":"code_challenge","in":"query","required":true,"description":"PKCE code challenge (RFC 7636).","schema":{"type":"string","pattern":"^[A-Za-z0-9._~-]{43,128}$"}},{"name":"code_challenge_method","in":"query","required":true,"description":"Always `S256`: PKCE is mandatory.","schema":{"type":"string","const":"S256"}},{"name":"state","in":"query","required":true,"description":"Returned to the client untouched.","schema":{"type":"string","minLength":1,"maxLength":4096}},{"name":"scope","in":"query","required":false,"description":"RFC 6749 §3.3 space-delimited list of scopes. Naming exactly one of `read`, `write`, `admin` asks for that one; naming several of them — the MCP reference client sends every `scopes_supported` value — or none asks for the default, `write`. Unknown names beside a known one are ignored; naming only unknown ones redirects with `invalid_scope`. The consent page shows the scope asked for, and the token response names the one granted.","schema":{"type":"string"}},{"name":"resource","in":"query","required":false,"description":"RFC 8707 resource indicator, optional: a request without one is for this deployment’s MCP URL, the one resource it serves. When sent, it must be that URL (`https://<host>/api/mcp`, exactly as the protected-resource metadata publishes it); any other redirects with `invalid_target`.","schema":{"type":"string","format":"uri"}}],"responses":{"302":{"description":"Redirect to the client `redirect_uri` with `error` (`invalid_request`, `invalid_scope` or `invalid_target`), `error_description`, `state` and `iss` — only once the client and the redirect validated. The description is Tre’s own text in the character set RFC 6749 §4.1.2.1 allows: `<field> is missing` or `<field> is invalid`, and for `invalid_scope` the scopes Tre grants — never the value the client sent."},"307":{"description":"Redirect to `/oauth/consent` once the request validates (setting the consent CSRF cookie), or to `/sign-in` when no web session is present."},"400":{"description":"HTML error page when the client or redirect_uri cannot be validated (never redirects to an unvalidated URI)."},"404":{"description":"OAuth door is off (`OAUTH_ENABLED` unset or not `true`)."},"429":{"description":"HTML error page: the per-user authorize budget is spent; `Retry-After` names the wait. Never a client redirect.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}}}},"500":{"description":"Unexpected failure — for example `AUTH_SECRET` unset when the validated request is sealed, or the session lookup failing. Never a client redirect."},"503":{"description":"HTML error page: the rate limiter is unavailable; `Retry-After` names the wait. Never a client redirect.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}}}}}}},"/oauth/token":{"post":{"operationId":"oauthToken","summary":"OAuth 2.1 token endpoint (authorization_code and refresh_token)","tags":["OAuth"],"security":[],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthTokenResponse"}}}},"400":{"description":"OAuth error: `invalid_request` (a form field that fails validation is named as `<field> is missing` or `<field> is invalid`), `invalid_grant`, `unsupported_grant_type`, or — on the token endpoint — `invalid_target`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"401":{"description":"invalid_client","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"404":{"description":"OAuth door is off (`OAUTH_ENABLED` unset or not `true`)."},"429":{"description":"Rate limited: `invalid_request`, and `Retry-After` names the wait.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"503":{"description":"server_error (dependency), with `Retry-After`.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}}},"description":"RFC 6749 token endpoint. Body is `application/x-www-form-urlencoded`. Answers 404 while `OAUTH_ENABLED` is off. No Tre bearer — clients authenticate with CIMD (`none` public clients or `private_key_jwt`). Access tokens last one hour; each refresh rotates the refresh token and grants it another 30 days (sliding), under an absolute cap of 90 days from the grant’s creation — past it the refresh answers `invalid_grant`, the grant is revoked, and the person consents again. Every refusal of an authorization code answers `invalid_grant` with the one description \"The authorization code is invalid\". A `resource` (RFC 8707) is optional; every one sent must be this server’s MCP endpoint, or the request answers `invalid_target`. Failures use the OAuth error object (`error` / `error_description`), not Tre’s `{ error: { code, message } }` shape.","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"oneOf":[{"type":"object","properties":{"grant_type":{"type":"string","const":"authorization_code"},"code":{"type":"string","minLength":20,"maxLength":200},"redirect_uri":{"type":"string","format":"uri"},"client_id":{"type":"string","format":"uri"},"code_verifier":{"type":"string","pattern":"^[A-Za-z0-9._~-]{43,128}$"},"client_assertion_type":{"type":"string","const":"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},"client_assertion":{"type":"string","minLength":20},"resource":{"description":"RFC 8707 resource indicator, optional. When sent (once or more), every value must be the MCP endpoint of this server (`https://<host>/api/mcp`, exactly as the protected-resource metadata publishes it); any other answers 400 `invalid_target`.","type":"string","format":"uri"}},"required":["grant_type","code","redirect_uri","client_id","code_verifier"]},{"type":"object","properties":{"grant_type":{"type":"string","const":"refresh_token"},"refresh_token":{"type":"string","minLength":20,"maxLength":200},"client_id":{"type":"string","format":"uri"},"client_assertion_type":{"type":"string","const":"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},"client_assertion":{"type":"string","minLength":20},"resource":{"description":"RFC 8707 resource indicator, optional. When sent (once or more), every value must be the MCP endpoint of this server (`https://<host>/api/mcp`, exactly as the protected-resource metadata publishes it); any other answers 400 `invalid_target`.","type":"string","format":"uri"}},"required":["grant_type","refresh_token","client_id"]}]}}}},"x-tre-internal":true}},"/oauth/revoke":{"post":{"operationId":"oauthRevoke","summary":"OAuth token revocation (RFC 7009)","tags":["OAuth"],"security":[],"responses":{"200":{"description":"Revoked, or token was already unknown","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthRevokeResponse"}}}},"400":{"description":"OAuth error: `invalid_request` (a form field that fails validation is named as `<field> is missing` or `<field> is invalid`), `invalid_grant`, `unsupported_grant_type`, or — on the token endpoint — `invalid_target`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"401":{"description":"invalid_client","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"404":{"description":"OAuth door is off (`OAUTH_ENABLED` unset or not `true`)."},"429":{"description":"Rate limited: `invalid_request`, and `Retry-After` names the wait.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"500":{"description":"server_error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}},"503":{"description":"server_error (dependency), with `Retry-After`.","headers":{"Retry-After":{"description":"Seconds to wait before retrying.","schema":{"type":"string"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OAuthErrorResponse"}}}}},"description":"Revokes an access or refresh token for the authenticated client. Unknown tokens are not an error (200 after successful client authentication). Answers 404 while `OAUTH_ENABLED` is off. No Tre bearer.","requestBody":{"required":true,"content":{"application/x-www-form-urlencoded":{"schema":{"type":"object","properties":{"token":{"type":"string","minLength":20,"maxLength":200},"client_id":{"type":"string","format":"uri"},"client_assertion_type":{"type":"string","const":"urn:ietf:params:oauth:client-assertion-type:jwt-bearer"},"client_assertion":{"type":"string","minLength":20}},"required":["token","client_id"]}}}},"x-tre-internal":true}}}}