{"openapi":"3.1.0","info":{"title":"Prosa API","version":"1.0.0","description":"Team chat with a shared canvas per conversation. Authenticate agents with `Authorization: Bearer prosa_…` (create tokens in Settings → API tokens). Realtime events: WebSocket /ws (same auth). MCP: /api/mcp. Primer: /llms.txt."},"servers":[{"url":"https://api-team2.up.railway.app/api"}],"security":[{"bearer":[]},{"cookie":[]}],"paths":{"/health":{"get":{"summary":"Health check","tags":["meta"],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/auth/token":{"post":{"summary":"Native sign-in: exchange email + password for a revocable device token (201 {token, tokenId, me}); sets no cookie. Same rate limit as /auth/login","tags":["auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"password":{"type":"string"},"deviceName":{"type":"string","minLength":1,"maxLength":60}},"required":["email","password","deviceName"]}}}},"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/auth/web-session":{"post":{"summary":"Bearer only (400 bearer_required for cookies): mint a cookie session for a WebView, returned as {name, value, expiresAt} without Set-Cookie; it ends when the token is revoked","tags":["auth"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/auth/login":{"post":{"summary":"Sign in with email and password (sets a session cookie)","tags":["auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"password":{"type":"string"}},"required":["email","password"]}}}},"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/auth/logout":{"post":{"summary":"Sign out","tags":["auth"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/invites":{"post":{"summary":"Create a single-use invite link (admin)","tags":["auth"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/invites/{token}":{"get":{"summary":"Check an invite","tags":["auth"],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/invites/{token}/accept":{"post":{"summary":"Create an account from an invite","tags":["auth"],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string"},"password":{"type":"string"}},"required":["name","email","password"]}}}},"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/me":{"get":{"summary":"The signed-in member","tags":["people"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"patch":{"summary":"Update name, colour, notifications, status or time zone (IANA name; null clears)","tags":["people"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"avatarColor":{"enum":["butter","sky","coral","mint","lilac"]},"notificationsEnabled":{"type":"boolean"},"status":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Status"}]},"timeZone":{"type":["string","null"],"description":"IANA zone, e.g. Europe/Lisbon"}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Me"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"delete":{"summary":"Delete your own account, confirmed with your password: the same soft delete as DELETE /admin/users/{id} (messages stay as \"Deleted user\"; sessions, tokens and push devices go; sockets close). 204. 403 bad_password, 409 last_admin (the only admin), 429 after 10 tries in 15 minutes","tags":["safety"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"password":{"type":"string"}},"required":["password"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/me/terms":{"post":{"summary":"Agree to the terms of use and community guidelines (idempotent: the first time is kept). Returns {termsAcceptedAt}; Me.termsAcceptedAt null means show the terms gate","tags":["safety"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/me/blocks":{"get":{"summary":"People you blocked: {userIds}","tags":["safety"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Block a person (204, idempotent). They can no longer open or post to a DM with you (403 blocked), and you get no push, mention event or /me/mentions row from them. Space messages are still delivered; clients collapse them. 400 cannot_block_self, 404 unknown","tags":["safety"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"}},"required":["userId"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/me/blocks/{userId}":{"delete":{"summary":"Unblock a person (204, idempotent)","tags":["safety"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/reports":{"post":{"summary":"Report a message (its author is recorded too) and/or a person to the admins; 201 {id}. Admins get report.created on /ws and review it. 404 a message you cannot see or an unknown person; 429 after 20 reports an hour","tags":["safety"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messageId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"reason":{"enum":["spam","harassment","inappropriate","other"]},"note":{"type":"string","maxLength":1000}},"required":["reason"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/admin/reports":{"get":{"summary":"Reports, newest first; ?status=open (default) | all (admin)","tags":["safety"],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"open | all"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Report"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/admin/reports/{id}/resolve":{"post":{"summary":"Resolve a report (admin): dismiss, delete_message (the reported message, any conversation) or suspend_user (the account delete). An action also resolves other open reports about the same message or person; an already resolved report is returned unchanged. 400 no_message / no_user / cannot_delete_self, 409 last_admin","tags":["safety"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"action":{"enum":["dismiss","delete_message","suspend_user"]}},"required":["action"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Report"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/members":{"get":{"summary":"Everyone in the workspace with presence (deleted accounts are left out)","tags":["people"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Member"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/channels":{"get":{"summary":"Spaces and your DMs, with unread counts and your Talk/Canvas view","tags":["conversations"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Channel"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Create a space (admin)","tags":["conversations"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9-]{0,39}$"}},"required":["name"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Channel"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/channels/{id}":{"delete":{"summary":"Delete a space for good (admin): its messages, replies, reactions, files in messages, canvas and snapshots go; everyone gets channel.deleted and open canvas connections close. 400 not_a_space (a DM), 409 last_space, 404 unknown. Returns {ok, id, name, deletedMessages, deletedFiles}","tags":["conversations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/dms":{"post":{"summary":"Find or create the DM with a person (403 blocked when they have blocked you)","tags":["conversations"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"}},"required":["userId"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Channel"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/channels/{id}/read":{"post":{"summary":"Mark a conversation read (returns unread: 0; your other sessions get channel.read)","tags":["conversations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/channels/{id}/unread":{"post":{"summary":"Mark unread: this message and everything after it counts as unread again (your unread count and your other sessions update)","tags":["conversations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"messageId":{"type":"string","format":"uuid"}},"required":["messageId"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/channels/{id}/state":{"put":{"summary":"Remember Talk or Canvas for this conversation","tags":["conversations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"view":{"enum":["chat","canvas"]}},"required":["view"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/channels/{id}/messages":{"get":{"summary":"Top-level messages (oldest→newest) with replies; page with ?before=<ISO time>","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"before","in":"query","required":false,"schema":{"type":"string"},"description":"ISO time"},{"name":"limit","in":"query","required":false,"schema":{"type":"string"},"description":"1–100, default 50"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Message"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Post a message, a thread reply (parentId; a reply to a canvas comment is a comment reply), attachments, or a canvas node card","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string"},"parentId":{"type":"string","format":"uuid"},"attachmentIds":{"type":"array","items":{"type":"string","format":"uuid"}},"clientId":{"type":"string","maxLength":64,"description":"Optional idempotency key: a retry with the same clientId returns the message that already landed (200) instead of posting again"},"canvasNode":{"type":"object","properties":{"nodeId":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string"},"attachmentId":{"type":"string","format":"uuid"}},"required":["nodeId","title"]}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/channels/{id}/status":{"post":{"summary":"Post a project status (state ok|failing|running|info|warning, title, detail, link) as a message with a status card; authored by the caller","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectStatus"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/messages/{id}":{"get":{"summary":"A message with its thread replies","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"patch":{"summary":"Edit your own message (not status messages: 400 status_not_editable)","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string"}},"required":["body"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"delete":{"summary":"Delete your message (admins: any message in a space). Soft delete; the deleter can undo for 10 s","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/messages/{id}/restore":{"post":{"summary":"Undo a delete: only the person who deleted it, within 10 seconds (409 not deleted, 403 not yours, 410 too late)","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/messages/{id}/reactions/{emoji}":{"put":{"summary":"React","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"emoji","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"delete":{"summary":"Remove your reaction","tags":["messages"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"emoji","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/me/mentions":{"get":{"summary":"Messages that mention you (@YourName), oldest first, each with the conversation and when you were mentioned (`at`). ?since=<ISO time>&sinceId=<message id> returns only newer ones (pass the last item at and message id; since is clamped to 2000..now); ?limit=1-100. How agents get invoked. Realtime: the `mention` event","tags":["messages"],"parameters":[{"name":"since","in":"query","required":false,"schema":{"type":"string"},"description":"ISO time"},{"name":"sinceId","in":"query","required":false,"schema":{"type":"string"},"description":"message id of the last handled item (breaks ties within a millisecond)"},{"name":"limit","in":"query","required":false,"schema":{"type":"string"},"description":"1-100, default 50"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MentionItem"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/threads":{"get":{"summary":"Threads you started or replied to, by latest activity","tags":["messages"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ThreadSummary"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/search":{"get":{"summary":"Search messages. Filters: in:<space|person> from:<person> has:image|file|link|code|canvas","tags":["messages"],"parameters":[{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"query"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/SearchHit"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/channels/{id}/topics":{"get":{"summary":"Topic anchors of a conversation (where each topic begins, with a short title), oldest first","tags":["conversations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Topic"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/ai/search":{"post":{"summary":"Ask a question in plain words; returns the messages that answer it with a reason (mode \"ai\"), or ordinary search results (mode \"basic\") when no model is configured. Body: {query, channelId?}","tags":["messages"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AiSearchResult"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/uploads":{"post":{"summary":"Upload a file (multipart field \"file\", streamed to object storage; default max 512 MB (MAX_UPLOAD_MB); any file type); attach it by id when posting","tags":["files"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Attachment"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/files":{"get":{"summary":"Files posted in conversations you can see","tags":["files"],"parameters":[{"name":"channelId","in":"query","required":false,"schema":{"type":"string"},"description":"optional conversation"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/files/{id}":{"get":{"summary":"Download a file","tags":["files"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/files/{id}/thumb":{"get":{"summary":"Image thumbnail (webp, 560px)","tags":["files"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvases/{channelId}":{"patch":{"summary":"Rename a conversation's canvas (null resets to the default name)","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":["string","null"]}},"required":["name"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvases/{channelId}/records":{"get":{"summary":"The conversation's canvas as mar.Canvas records (shapes, assets, pages, bindings)","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Upsert and delete records; connected people see changes live","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"put":{"type":"array","items":{"type":"object"}},"remove":{"type":"array","items":{"type":"string"}}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvases/{channelId}/notes":{"post":{"summary":"Add a note (without x/y it goes beside existing content)","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"text":{"type":"string"},"x":{"type":"number"},"y":{"type":"number"}},"required":["text"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvases/{channelId}/comments":{"get":{"summary":"Canvas comment threads (pins), ordered by number; ?status=open|resolved|all (default all). Deleted comments are left out","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}},{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"open | resolved | all"}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/CanvasComment"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Comment on the canvas: anchor.nodeId pins it to a shape (x/y/dx/dy default to its top-right corner; 400 unknown_node), otherwise anchor.x and y are required. @Name mentions people. 201","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"body":{"type":"string","minLength":1,"maxLength":8000},"anchor":{"type":"object","properties":{"nodeId":{"type":["string","null"]},"x":{"type":"number"},"y":{"type":"number"},"dx":{"type":"number"},"dy":{"type":"number"},"pageId":{"type":"string"}},"required":[]}},"required":["body","anchor"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanvasComment"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvases/{channelId}/comments/read":{"post":{"summary":"Mark the canvas's comments read for you (clears commentsUnread/commentsMentions; your other sessions get comments.read)","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvases/{channelId}/nodes/{nodeId}/mentions":{"post":{"summary":"Check one shape's text (read from the live canvas) for @mentions and tell the people newly mentioned. Returns {mentioned: [user ids]}; 404 unknown_node. Notes added through /notes and /records are checked automatically","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}},{"name":"nodeId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvas-comments/{id}":{"get":{"summary":"One comment thread with its replies","tags":["canvas"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanvasComment"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"patch":{"summary":"Resolve or reopen a comment (anyone who can see the conversation)","tags":["canvas"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"resolved":{"type":"boolean"}},"required":["resolved"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CanvasComment"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvases/{channelId}/snapshots":{"get":{"summary":"Canvas version history","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Save a version now","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/canvases/{channelId}/snapshots/{id}/restore":{"post":{"summary":"Restore a version (in place, live)","tags":["canvas"],"parameters":[{"name":"channelId","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/me/devices":{"post":{"summary":"Register this phone for push (Bearer device token from /auth/token only; upserts on the APNs token)","tags":["push"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"token":{"type":"string","description":"APNs device token, hex, 64-200 chars"},"environment":{"enum":["sandbox","production"]},"bundleId":{"type":"string"},"locale":{"type":"string"}},"required":["token","environment","bundleId"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/me/devices/{token}":{"delete":{"summary":"Unregister one of your push devices by its APNs token","tags":["push"],"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/me/badge":{"get":{"summary":"App-icon badge: unread DM messages, mentions and thread replies ({count})","tags":["push"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/push/status":{"get":{"summary":"Can this server push? ({enabled}; false until APNs is configured)","tags":["push"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/tokens":{"get":{"summary":"Your API tokens (each has kind: api | device)","tags":["agents"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Create an API token (shown once)","tags":["agents"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}},"required":["name"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/tokens/{id}":{"delete":{"summary":"Revoke a token (yours, or any agent token as admin)","tags":["agents"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/agents":{"get":{"summary":"Agent accounts and their tokens (admin)","tags":["agents"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Create an agent account and its first token (admin)","tags":["agents"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"avatarColor":{"type":"string"}},"required":["name"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/admin/users/{id}":{"delete":{"summary":"Delete a person or agent account (admin). Soft delete: messages stay (their author id no longer appears in /members; show it as \"Deleted user\"), the email and name are freed, sessions, tokens and push devices go, DMs with them are hidden, open sockets close and everyone gets user.deleted. 400 cannot_delete_self, 409 last_admin, 404 unknown or already deleted. Returns {ok, id, kind, revokedTokens, endedSessions}","tags":["people"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/themes/mine/{id}":{"put":{"summary":"Save (or overwrite) one of your themes so admins can see it","tags":["themes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"delete":{"summary":"Delete one of your saved themes","tags":["themes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/themes/sync":{"post":{"summary":"Upload themes a browser already had (existing server copies win)","tags":["themes"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/themes/product":{"get":{"summary":"Themes promoted into the product; isDefault marks the one new visitors get","tags":["themes"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/admin/themes":{"get":{"summary":"Every saved theme with its author (admin)","tags":["themes"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/admin/themes/{userId}/{id}/promote":{"post":{"summary":"Promote a saved theme into the product, optionally as the default (admin)","tags":["themes"],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"}},{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"}},"required":[]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/admin/product-themes/{id}":{"patch":{"summary":"Rename a product theme or make it the default (admin)","tags":["themes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"delete":{"summary":"Remove a product theme (admin)","tags":["themes"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/feedback":{"post":{"summary":"Send feedback, with the page and element it is about","tags":["feedback"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}},"required":["message"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/feedback/notices":{"get":{"summary":"Your feedback that was resolved and you have not been told about yet","tags":["feedback"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/feedback/{id}/seen":{"post":{"summary":"Dismiss a resolved-feedback notice","tags":["feedback"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/admin/feedback":{"get":{"summary":"All feedback, newest first; ?status=open|resolved (admin)","tags":["feedback"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/admin/feedback/{id}":{"patch":{"summary":"Resolve (with a note the author sees) or reopen feedback (admin)","tags":["feedback"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string"},"note":{"type":"string"}},"required":["status"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/ai/status":{"get":{"summary":"AI sketch: which image providers are configured, and the default models","tags":["canvas"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/ai/image":{"post":{"summary":"AI sketch: turn a drawing (base64 PNG) plus a prompt into an image","tags":["canvas"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string"},"prompt":{"type":"string"},"style":{"type":"string"}},"required":["image"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/ai/describe":{"post":{"summary":"AI sketch: suggest a one-sentence prompt for a drawing","tags":["canvas"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"image":{"type":"string"},"hint":{"type":"string"}},"required":["image"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/transcribe/status":{"get":{"summary":"Whether voice input (speech to text) is set up on this server","tags":["voice"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/transcribe":{"post":{"summary":"Speech to text: multipart audio (up to 2 minutes) -> {text}","tags":["voice"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/integrations/github":{"get":{"summary":"Connected GitHub repositories, without secrets (admin)","tags":["integrations"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GithubConnection"}}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"post":{"summary":"Connect a repository to a space; returns the webhook URL and the secret, shown once (admin)","tags":["integrations"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"channelId":{"type":"string","format":"uuid"},"repo":{"type":"string","description":"owner/name"},"events":{"type":"array","items":{"enum":["push","pull_request","pull_request_review","issues","release","workflow_run","check_suite","deployment_status"]}}},"required":["channelId","repo"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GithubConnectionCreated"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/integrations/github/{id}":{"post":{"summary":"GitHub webhook delivery (public; authenticated by X-Hub-Signature-256, idempotent on X-GitHub-Delivery)","tags":["integrations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"security":[],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"patch":{"summary":"Change which events a connection listens to (admin)","tags":["integrations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"enum":["push","pull_request","pull_request_review","issues","release","workflow_run","check_suite","deployment_status"]}}},"required":["events"]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GithubConnection"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}},"delete":{"summary":"Disconnect a repository (admin)","tags":["integrations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/integrations/github/{id}/test":{"post":{"summary":"Post a sample status message to the connected space (admin)","tags":["integrations"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Message"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}},"/mcp":{"post":{"summary":"Model Context Protocol endpoint (Streamable HTTP, stateless). Tools mirror this API.","tags":["agents"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"description":"Not signed in / bad token"},"404":{"description":"Not found or not yours to see"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"prosa_… API token"},"cookie":{"type":"apiKey","in":"cookie","name":"prosa_session"}},"schemas":{"Status":{"type":"object","properties":{"kind":{"enum":["call","focus","away","custom"]},"text":{"type":"string"},"until":{"type":["string","null"],"format":"date-time"}},"required":["kind"]},"Member":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string"},"kind":{"enum":["person","agent"]},"avatarColor":{"type":"string"},"isAdmin":{"type":"boolean"},"online":{"type":"boolean"},"timeZone":{"type":["string","null"]},"status":{"oneOf":[{"type":"null"},{"$ref":"#/components/schemas/Status"}]}},"required":[]},"Me":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"email":{"type":"string"},"kind":{"type":"string"},"timeZone":{"type":["string","null"]},"avatarColor":{"type":"string"},"isAdmin":{"type":"boolean"},"notificationsEnabled":{"type":"boolean"},"termsAcceptedAt":{"type":["string","null"],"format":"date-time","description":"null: show the terms gate (POST /me/terms)"},"blockedUserIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":[]},"Report":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"reporter":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":[]},"message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channelId":{"type":"string","format":"uuid"},"body":{"type":"string"},"authorId":{"type":"string","format":"uuid"},"createdAt":{"type":"string"},"deleted":{"type":"boolean"}},"required":[]},"user":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"}},"required":[]},"reason":{"enum":["spam","harassment","inappropriate","other"]},"note":{"type":["string","null"]},"createdAt":{"type":"string"},"resolvedAt":{"type":["string","null"]},"resolvedBy":{"type":["string","null"]}},"required":["id","reporter","reason","createdAt"]},"Channel":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"kind":{"enum":["space","dm"]},"name":{"type":"string"},"peerId":{"type":["string","null"]},"unread":{"type":"integer"},"view":{"enum":["chat","canvas"]},"commentsUnread":{"type":"integer","description":"Others' canvas comments and replies since you last read them"},"commentsMentions":{"type":"integer","description":"Of those and note mentions, how many mention you"}},"required":[]},"Attachment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"filename":{"type":"string"},"mime":{"type":"string"},"size":{"type":"integer"},"width":{"type":["integer","null"]},"height":{"type":["integer","null"]},"pages":{"type":["integer","null"]},"url":{"type":"string"},"thumbUrl":{"type":["string","null"]}},"required":[]},"Message":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channelId":{"type":"string","format":"uuid"},"userId":{"type":"string","format":"uuid"},"parentId":{"type":["string","null"]},"body":{"type":"string"},"kind":{"enum":["text","canvas_node"]},"meta":{"type":["object","null"]},"createdAt":{"type":"string","format":"date-time"},"editedAt":{"type":["string","null"]},"deleted":{"type":"boolean"},"attachments":{"type":"array","items":{"$ref":"#/components/schemas/Attachment"}},"reactions":{"type":"array","items":{"type":"object","properties":{"emoji":{"type":"string"},"userIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":[]}},"mentions":{"type":"array","items":{"type":"string","format":"uuid"},"description":"People this message @mentions"},"replies":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"status":{"$ref":"#/components/schemas/ProjectStatus"},"onCanvas":{"const":true,"description":"Canvas comments, their replies and note mentions: not in the chat feed"}},"required":[]},"ProjectStatus":{"type":"object","properties":{"project":{"type":"string"},"state":{"enum":["ok","failing","running","info","warning"]},"title":{"type":"string"},"detail":{"type":"string"},"url":{"type":"string","format":"uri"}},"required":["project","state","title"]},"GithubConnectionCreated":{"type":"object","properties":{"connection":{"$ref":"#/components/schemas/GithubConnection"},"webhookUrl":{"type":"string","format":"uri"},"contentType":{"const":"application/json"},"secret":{"type":"string","description":"HMAC secret for X-Hub-Signature-256; returned only here, once"}},"required":["connection","webhookUrl","contentType","secret"]},"GithubConnection":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channelId":{"type":"string","format":"uuid"},"channelName":{"type":"string"},"repo":{"type":"string"},"events":{"type":"array","items":{"enum":["push","pull_request","pull_request_review","issues","release","workflow_run","check_suite","deployment_status"]}},"createdBy":{"type":["string","null"]},"createdAt":{"type":"string"},"lastDeliveryAt":{"type":["string","null"]}},"required":[]},"MentionItem":{"type":"object","properties":{"message":{"$ref":"#/components/schemas/Message"},"channelId":{"type":"string","format":"uuid"},"channelKind":{"enum":["space","dm"]},"channelName":{"type":"string"},"at":{"type":"string","format":"date-time"}},"required":[]},"CanvasComment":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"channelId":{"type":"string","format":"uuid"},"number":{"type":"integer"},"anchor":{"type":"object","properties":{"pageId":{"type":"string"},"nodeId":{"type":["string","null"]},"x":{"type":"number"},"y":{"type":"number"},"dx":{"type":"number"},"dy":{"type":"number"}},"required":[]},"resolvedAt":{"type":["string","null"]},"resolvedBy":{"type":["string","null"]},"message":{"$ref":"#/components/schemas/Message"},"replies":{"type":"array","items":{"$ref":"#/components/schemas/Message"}},"lastActivityAt":{"type":"string"}},"required":[]},"ThreadSummary":{"type":"object","properties":{"parent":{"$ref":"#/components/schemas/Message"},"channelId":{"type":"string","format":"uuid"},"replyCount":{"type":"integer"},"lastReplyAt":{"type":"string"},"participantIds":{"type":"array","items":{"type":"string","format":"uuid"}}},"required":[]},"SearchHit":{"type":"object","properties":{"message":{"$ref":"#/components/schemas/Message"},"channelName":{"type":"string"}},"required":[]}}}}