{"openapi":"3.1.0","info":{"title":"Kazee Chat API","version":"0.5.1","description":"Everything a person can do in Kazee Chat (chats, messages, threads, files, stories, calls and meetings) as plain HTTPS calls that answer in JSON.\n\n**Sign in.** Send `Authorization: Bearer <token>` with every call. The token comes from Kazee sign-in, and each call lists the permission it needs.\n\n**IDs and dates.** IDs are 24-character strings. Dates are ISO 8601 in UTC, e.g. `2026-10-20T09:00:00.000Z`.\n\n**Your user ID.** Many calls want your own user ID, in the path (`{userId}`) or as an input such as `sender`; a bot's is its own ID. Chat has no call that tells you who you are: ask Kazee sign-in with the same token, `GET https://central.inet.africa/api/principal/me`, and use `principal.id` from its reply (this works for person and bot tokens; for an app signed in through Kazee sign-in it is the `sub` of the ID token it got).\n\n**Path names.** Most calls name a chat `{chatId}` in the path. Three older calls name it `{chat_id}`: `POST /chat/{chat_id}/message` (Send a message), `POST /chat/{chat_id}/participant` (Change a group's members) and `DELETE /chat/{chat_id}` (Delete a chat). It is the same chat ID, only spelt differently; those three also spell their other inputs with underscores (`user_id`, `requester_id`, `media_id`).\n\n**Errors.** A call that fails answers with a 4xx or 5xx status and `{ \"error\": \"what went wrong\" }`.\n\n**Live updates.** New messages, typing and calls also arrive over a socket.io connection at `/socket.io`; that part gets its own page later.\n\n**For bots.** This page is built from the Chat code itself. The raw file is at `/api/swagger`."},"tags":[{"name":"Chats","description":"Direct chats, group chats and channels: create, list, read, update, members and outside-system apps."},{"name":"Messages","description":"Send, read, edit, pin and delete messages, mentions and interactive cards."},{"name":"Threads","description":"Reply threads under a message: start, read, follow, archive and rename."},{"name":"Chat folders","description":"A person's own folders for sorting their chat list."},{"name":"Media & files","description":"Upload and download files, list a chat's files and links, open documents for editing."},{"name":"Stories","description":"Stories, their viewers, reactions and comments."},{"name":"Calls","description":"Call history, call set-up details and phone calls through the office phone system."},{"name":"Meetings","description":"Meeting rooms and invitations."},{"name":"People","description":"People in the organisation, their profiles and who is online."},{"name":"Settings","description":"A person's own preferences, mutes and device push registration."},{"name":"Attendance","description":"Check in and out of work."},{"name":"Search","description":"Search messages, or everything at once."},{"name":"Notifications","description":"A person's notifications."},{"name":"Bots","description":"A bot's own commands and apps."},{"name":"Apps","description":"Bot apps opened from a chat, and one-time app passes."},{"name":"Company settings"}],"paths":{"/chats/{userId}/{chatType}":{"get":{"tags":["Chats"],"summary":"List my chats","description":"Lists your chats of one type, each with its members, newest message, your unread and mention counts and your own settings (pinned, archived, marked unread). Pinned chats come first, then the most recently active, counting replies in threads you follow. Meeting rooms of a single calendar occurrence are left out until they have a message. The reply says Cache-Control: private, max-age=30, so your browser or HTTP client may reuse it for 30 seconds; nothing on the server clears that, not even creating a chat. New chats and messages arrive live.\n\n**Permission:** `chat.chats.read` (Read chats).","operationId":"getChats","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","example":"66f1b2c3d4e5f60718293a4b"},{"name":"chatType","in":"path","required":true,"schema":{"type":"string","enum":["chat","comment","external","notifications"]},"description":"Which chats to list. chat lists direct chats, groups and channels, and also your notifications chat; comment lists the comment chats of tasks and other items","example":"chat"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"chats":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Chat ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"participants":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"The person's user ID"},"name":{"type":"string","description":"Their name"},"email":{"type":"string","description":"Their email address"},"phone":{"type":"string","description":"Their phone number"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"},"profilePhoto":{"type":"string","description":"Address of their photo (the small copy when there is one), or null"},"online":{"type":"boolean","description":"Whether they are connected to Chat now"},"lastSeen":{"type":"string","format":"date-time","description":"When they were last connected, or null when unknown"},"inCall":{"type":"boolean","description":"Whether they are in a call now"},"inCallKind":{"description":"internal for a Kazee call, external for a phone call through the office phone system; null when not in a call"}}},"description":"The members, as chat-list rows"},"lastMessage":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"type":{"type":"string"},"profilePhoto":{"type":"string"}},"description":"Who sent it (_id, name, email, phone, type, profilePhoto)"},"content":{"type":"string","description":"Its text"},"type":{"type":"string","description":"text, image, video, file, audio, call, location, system, poll, story_reply, interactive, notification or deleted"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions"},"reactions":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"userId":{"type":"string"},"emoji":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"description":"Emoji reactions (userId, emoji, createdAt)"},"medias":{"type":"array","description":"Files attached to it"},"edited":{"type":"boolean","description":"Whether it was edited"},"isDeleted":{"type":"boolean","description":"Whether it was deleted"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was stored"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"The newest message in the chat itself (not in a thread); absent when there is none"},"chatName":{"type":"string","description":"The group's name; for a direct chat, the other person's name"},"profilePhoto":{"type":"string","description":"Address of the group's photo; for a direct chat, the other person's photo; null when there is none"},"description":{"type":"string","description":"What the group is for"},"isGroupChat":{"type":"boolean","description":"true for a group or channel, false for a direct chat"},"groupAdmins":{"type":"array","items":{"type":"string"},"description":"IDs of the group's admins"},"assistantAction":{"type":"string","description":"How bots answer here: assistant_tagged_reply (only when tagged or replied to), assistant_passive (read everything, reply when they can help) or assistant_free_reply (reply to everything)"},"chatType":{"type":"string","description":"chat, comment (a comment chat of a task or other item), external or notifications"},"seq":{"type":"integer","description":"Number of the chat's latest change; pass it as this chat's cursor to syncChanges"},"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"messageId":{"type":"string"},"pinnedBy":{"type":"string"},"pinnedAt":{"type":"string","format":"date-time"},"notifyMode":{"type":"string"}}},"description":"Pinned messages (messageId, pinnedBy, pinnedAt, notifyMode)"},"createdAt":{"type":"string","format":"date-time","description":"When the chat was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last had activity or changed"},"__v":{"type":"integer","description":"Internal revision counter"},"markedUnread":{"type":"boolean","description":"Whether you marked the chat as unread"},"isPinned":{"type":"boolean","description":"Whether you pinned it to the top of your list"},"pinnedAt":{"type":"string","format":"date-time","description":"When you pinned it, or null"},"isArchived":{"type":"boolean","description":"Whether you archived it"},"archiveVersion":{"type":"integer","description":"How many times you archived or restored it; pass it as expectedVersion to setChatArchived"},"threadActivityAt":{"type":"string","format":"date-time","description":"When a thread you follow here last had a reply, or null"},"unreadMessagesCount":{"type":"integer","description":"Messages from others you have not read"},"unreadMentionsCount":{"type":"integer","description":"How many of those mention you"}}},"description":"Your chats of that type: pinned ones first, then the most recently active"}}},"example":{"chats":[{"_id":"6ad1d0a1c2b3a4f5e6d7c801","organizationId":"66a4b275003d1b495212b5aa","participants":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina@inet.africa","phone":"+254712345678","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","online":true,"lastSeen":"2026-10-16T08:55:00.000Z","inCall":false,"inCallKind":null},{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian@inet.africa","phone":"+254722334455","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","online":false,"lastSeen":"2026-10-16T07:40:00.000Z","inCall":false,"inCallKind":null}],"lastMessage":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian@inet.africa","phone":"+254722334455","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a"},"content":"The October fibre invoice is in, please approve by Friday.","type":"text","mentions":["66f1b2c3d4e5f60718293a4b"],"reactions":[{"_id":"6ad1d0b2c3d4e5f6a7b8c9f1","userId":"66f1b2c3d4e5f60718293a4b","emoji":"👍","createdAt":"2026-10-16T09:12:00.000Z"}],"medias":[],"edited":false,"isDeleted":false,"timestamp":"2026-10-16T09:10:00.000Z","createdAt":"2026-10-16T09:10:00.000Z","updatedAt":"2026-10-16T09:12:00.000Z","__v":0},"chatName":"Finance team","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","description":"Invoices, payments and month-end","isGroupChat":true,"groupAdmins":["66f1b2c3d4e5f60718293a4b"],"assistantAction":"assistant_tagged_reply","chatType":"chat","seq":42,"pinnedMessages":[{"_id":"6ad1d1c9d0e1f2a3b4c5d601","messageId":"6ad1d0b2c3d4e5f6a7b8c902","pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedAt":"2026-10-14T06:30:00.000Z","notifyMode":"notify"}],"createdAt":"2026-09-01T07:00:00.000Z","updatedAt":"2026-10-16T09:10:00.000Z","__v":3,"markedUnread":false,"isPinned":true,"pinnedAt":"2026-10-02T08:00:00.000Z","isArchived":false,"archiveVersion":0,"threadActivityAt":"2026-10-16T09:20:00.000Z","unreadMessagesCount":3,"unreadMentionsCount":1}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.read"]}],"x-required-scopes":["chat.chats.read"]}},"/chats/{chatId}":{"get":{"tags":["Chats"],"summary":"Get a chat","description":"Gets one chat you are a member of, with every member's whole profile and online state, its admins' profiles, its pinned messages and whether you archived it. The chat's fields sit at the top level of the reply. The photo comes back as stored, not as an address.\n\n**Permission:** `chat.chats.read` (Read chats).","operationId":"getChat","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"_id":{"type":"string","description":"Chat ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"participants":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"The person's user ID"},"name":{"type":"string","description":"Their name"},"email":{"type":"string","description":"Their email address"},"phone":{"type":"string","description":"Their phone number"},"organizationId":{"type":"string","description":"ID of their organisation"},"role":{"type":"string","description":"Their role in the organisation"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"},"onboarded":{"type":"boolean","description":"Whether they finished first-time setup"},"pbxExtension":{"type":"string","description":"Their extension on the office phone system, if any"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}},"description":"Their photo as stored"},"commands":{"type":"array","description":"Slash commands a bot offers; empty for people"},"createdAt":{"type":"string","format":"date-time","description":"When they were added to Chat"},"updatedAt":{"type":"string","format":"date-time","description":"When their profile last changed"},"__v":{"type":"integer","description":"Internal revision counter"},"online":{"type":"boolean","description":"Whether they are connected to Chat now"},"lastSeen":{"type":"string","format":"date-time","description":"When they were last connected; absent when unknown"}}},"description":"The members, each with their whole profile and online state"},"lastMessage":{"type":"object","properties":{"_id":{"type":"string"},"sender":{"type":"string"}},"description":"The newest message: its _id, sender ID and, when set, its file and the message it replies to"},"chatName":{"type":"string","description":"The group's name, or the name given to a direct chat"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}},"description":"The group's photo as stored (minioPath, bucketName, thumbMinioPath, thumbBucketName)"},"description":{"type":"string","description":"What the group is for"},"isGroupChat":{"type":"boolean","description":"true for a group or channel, false for a direct chat"},"groupAdmins":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"organizationId":{"type":"string"},"role":{"type":"string"},"type":{"type":"string"},"onboarded":{"type":"boolean"},"pbxExtension":{"type":"string"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}}},"commands":{"type":"array"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"__v":{"type":"integer"}}},"description":"The group's admins, each with their whole profile"},"assistantAction":{"type":"string","description":"How bots answer here: assistant_tagged_reply (only when tagged or replied to), assistant_passive (read everything, reply when they can help) or assistant_free_reply (reply to everything)"},"chatType":{"type":"string","description":"chat, comment (a comment chat of a task or other item), external or notifications"},"seq":{"type":"integer","description":"Number of the chat's latest change; pass it as this chat's cursor to syncChanges"},"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"messageId":{"type":"object","properties":{"_id":{"type":"string"},"content":{"type":"string"},"type":{"type":"string"},"sender":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}}},"type":{"type":"string"}}},"timestamp":{"type":"string","format":"date-time"}}},"pinnedBy":{"type":"string"},"pinnedAt":{"type":"string","format":"date-time"},"notifyMode":{"type":"string"}}},"description":"Pinned messages, each with the message's text, type, sender and time"},"createdAt":{"type":"string","format":"date-time","description":"When the chat was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last had activity or changed"},"__v":{"type":"integer","description":"Internal revision counter"},"isArchived":{"type":"boolean","description":"Whether you archived the chat"},"archiveVersion":{"type":"integer","description":"How many times you archived or restored it; pass it as expectedVersion to setChatArchived"}}},"example":{"_id":"6ad1d0a1c2b3a4f5e6d7c801","organizationId":"66a4b275003d1b495212b5aa","participants":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina@inet.africa","phone":"+254712345678","organizationId":"66a4b275003d1b495212b5aa","role":"Admin","type":"Human","onboarded":true,"pbxExtension":"2041","profilePhoto":{"minioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"commands":[],"createdAt":"2026-08-20T07:00:00.000Z","updatedAt":"2026-10-16T08:55:00.000Z","__v":0,"online":true,"lastSeen":"2026-10-16T08:55:00.000Z"}],"lastMessage":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","sender":"66f1b2c3d4e5f60718293a5c"},"chatName":"Finance team","profilePhoto":{"minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"description":"Invoices, payments and month-end","isGroupChat":true,"groupAdmins":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina@inet.africa","phone":"+254712345678","organizationId":"66a4b275003d1b495212b5aa","role":"Admin","type":"Human","onboarded":true,"pbxExtension":"2041","profilePhoto":{"minioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"commands":[],"createdAt":"2026-08-20T07:00:00.000Z","updatedAt":"2026-10-16T08:55:00.000Z","__v":0}],"assistantAction":"assistant_tagged_reply","chatType":"chat","seq":42,"pinnedMessages":[{"_id":"6ad1d1c9d0e1f2a3b4c5d601","messageId":{"_id":"6ad1d0b2c3d4e5f6a7b8c902","content":"Month-end close starts on the 28th.","type":"text","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":{"minioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"type":"Human"},"timestamp":"2026-10-14T06:29:00.000Z"},"pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedAt":"2026-10-14T06:30:00.000Z","notifyMode":"notify"}],"createdAt":"2026-09-01T07:00:00.000Z","updatedAt":"2026-10-16T09:10:00.000Z","__v":3,"isArchived":false,"archiveVersion":0}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"chatId is not a valid ID, or the chat could not be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.read"]}],"x-required-scopes":["chat.chats.read"]}},"/messages/{chatId}/{userId}":{"get":{"tags":["Messages"],"summary":"List a chat's messages","description":"Lists a chat you are a member of, one page at a time from the newest end, with your unread count. Instead of a page number you can page with before (older messages) or after (newer messages), or catch up with since: every message created, edited or deleted after that time, up to 500. Deleted messages stay in place with type deleted. Set threads to true to leave out thread replies that stay in their thread (read them with getThread).\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getMessages","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"after","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Return the messageCount messages just after this time (the previous page's cursor.after)","example":"2026-10-15T17:30:00.000Z"},{"name":"before","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Return the messageCount messages just before this time (the previous page's cursor.before). Wins over after","example":"2026-10-16T05:12:03.000Z"},{"name":"messageCount","in":"query","required":false,"schema":{"type":"integer","default":100},"description":"Messages per page (also with before and after)","example":50},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1},"description":"Page number, counting from the newest messages; ignored with since, before or after","example":1},{"name":"since","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Catch up: return every message created, edited or deleted after this time, oldest first, at most 500. Wins over before and after","example":"2026-10-16T05:00:00.000Z"},{"name":"threads","in":"query","required":false,"schema":{"type":"boolean"},"description":"true (or 1) to leave out thread replies that stay in their thread. Without it they are listed inline, as older apps expect","example":true}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"data":{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"File ID; pass it as media_id when sending"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it was uploaded to"},"sender":{"type":"string","description":"ID of the person who uploaded it"},"messageId":{"type":"string","description":"ID of the message it is attached to"},"url":{"type":"string","description":"Signed link to download it, valid for up to 7 days"},"type":{"type":"string","description":"image, video or file"},"bucketName":{"type":"string","description":"Which store holds it"},"fileName":{"type":"string","description":"Its name as uploaded"},"minioPath":{"type":"string","description":"Key of the stored file"},"thumbHash":{"type":"string","description":"Tiny blurred placeholder to show while it loads; absent on older files"},"width":{"type":"integer","description":"Width in pixels (photos and videos); absent on older files"},"height":{"type":"integer","description":"Height in pixels (photos and videos); absent on older files"},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"minioPath":{"type":"string"},"bucketName":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"}},"description":"Small preview (640 px on the long edge) with its own signed url, minioPath, bucketName, width and height; absent until one is made"},"createdAt":{"type":"string","format":"date-time","description":"When it was uploaded"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"}}},"description":"Files attached to it"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions (everyone in the chat for @all)"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"Who reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"},"_id":{"type":"string","description":"ID of the reaction"}}},"description":"Emoji reactions to it"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"}}},"description":"The messages, oldest first. Keys only some messages carry appear only when set: replyTo (the quoted message, filled in with its sender and files), replyToMediaId, replyToChat and replyToChatName, threadRoot and alsoInChannel (a thread reply), threadReplyCount, threadLastReplyAt, threadParticipants, threadTitle, threadTitleBy, threadTitleAt and threadStart (a thread's root), location, linkPreview, card (a bot's Kazee Card with its public state, plus your own answer as card.mine), forwardedFrom, storyRef, systemData, editedAt, deletedAt and findMeCode"},"pagination":{"type":"object","properties":{"currentPage":{"type":"integer","description":"The page asked for, as you sent it (sent in the query it comes back as text, e.g. \"2\"); 1 when left out"},"messageCount":{"type":"string","description":"Messages per page, as you sent it (text when sent in the query); 100 when left out"},"totalMessages":{"type":"integer","description":"How many messages the chat has (0 with before or after)"},"totalPages":{"type":"integer","description":"How many pages that makes (0 with before or after)"}},"description":"Where this page sits"},"cursor":{"type":"object","properties":{"before":{"type":"string","format":"date-time","description":"With before: the time of the oldest message returned (your before when none came back). Pass it as before to get the next older page"},"hasMore":{"type":"boolean","description":"With before: whether older messages exist; false when this page was not full"}},"description":"Only with before or after: where the next page starts"},"unreadCount":{"type":"integer","description":"How many messages in the chat you have not read (thread replies that stay in their thread are counted per thread instead)"},"oldestUnreadMessageId":{"type":"string","description":"ID of the oldest of those, to scroll to; null when there are none"}},"description":"The page. This example is a page asked for with before, the usual way to scroll back. With a page number (no before or after) there is no cursor and pagination has real totals. With after, cursor is { after: the newest message's time, to pass as after next; hasMoreAfter } instead. With since, data is { messages, syncMode: true, since, messageCount, unreadCount, oldestUnreadMessageId } instead"}}},"example":{"success":true,"data":{"messages":[{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","status":"delivered","type":"image","interactive":{"buttons":[]},"medias":[{"_id":"6ad1d0d4e5f6a7b8c9dae101","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":"66f1b2c3d4e5f60718293a4b","messageId":"6ad1d0b2c3d4e5f6a7b8c901","url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"image","bucketName":"org-66a4b275003d1b495212b5aa","fileName":"delivery-note-october.jpg","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg","thumbHash":"1QcSHQRnh493V4dIh4eXh1h4kJUI","width":1600,"height":1200,"thumbnail":{"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg","bucketName":"org-66a4b275003d1b495212b5aa","width":640,"height":480},"createdAt":"2026-10-16T05:12:01.000Z","updatedAt":"2026-10-16T05:12:03.000Z","__v":0}],"viewedBy":["66f1b2c3d4e5f60718293a5c"],"mentions":["66f1b2c3d4e5f60718293a5c"],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","emoji":"👍","createdAt":"2026-10-16T05:14:40.000Z","_id":"6ad1d0f7b8c9daebfc0d1e01"}],"timestamp":"2026-10-16T05:12:03.000Z","createdAt":"2026-10-16T05:12:03.000Z","updatedAt":"2026-10-16T05:14:40.000Z","__v":0}],"pagination":{"currentPage":1,"messageCount":"50","totalMessages":0,"totalPages":0},"cursor":{"before":"2026-10-16T05:12:03.000Z","hasMore":true},"unreadCount":2,"oldestUnreadMessageId":"6ad1d0b2c3d4e5f6a7b8c901"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No chat with that ID that you are a member of, chatId is not a valid ID, or since, before or after is not a valid date","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/messages/{chatId}/{userId}/around/{anchorMessageId}":{"get":{"tags":["Messages"],"summary":"Load messages around a message","description":"Loads the messages just before and after one message in a chat you are a member of, for jumping to a link, a search hit or your first unread message, with your unread count. With threads set to true, a reply that stays in its thread is shown at its root's place and the reply says which thread to open.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getMessagesAround","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"anchorMessageId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the message to centre on; it must be in this chat","example":"6ad1d0b2c3d4e5f6a7b8c901"},{"name":"after","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"How many messages to return after it (0 means 25)","example":20},{"name":"before","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"How many messages to return before it (0 means 25)","example":20},{"name":"threads","in":"query","required":false,"schema":{"type":"boolean"},"description":"true (or 1) to leave out thread replies that stay in their thread and to open a thread for such a reply. Without it they are listed inline, as older apps expect","example":true}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"data":{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"File ID; pass it as media_id when sending"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it was uploaded to"},"sender":{"type":"string","description":"ID of the person who uploaded it"},"messageId":{"type":"string","description":"ID of the message it is attached to"},"url":{"type":"string","description":"Signed link to download it, valid for up to 7 days"},"type":{"type":"string","description":"image, video or file"},"bucketName":{"type":"string","description":"Which store holds it"},"fileName":{"type":"string","description":"Its name as uploaded"},"minioPath":{"type":"string","description":"Key of the stored file"},"thumbHash":{"type":"string","description":"Tiny blurred placeholder to show while it loads; absent on older files"},"width":{"type":"integer","description":"Width in pixels (photos and videos); absent on older files"},"height":{"type":"integer","description":"Height in pixels (photos and videos); absent on older files"},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"minioPath":{"type":"string"},"bucketName":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"}},"description":"Small preview (640 px on the long edge) with its own signed url, minioPath, bucketName, width and height; absent until one is made"},"createdAt":{"type":"string","format":"date-time","description":"When it was uploaded"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"}}},"description":"Files attached to it"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions (everyone in the chat for @all)"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"Who reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"},"_id":{"type":"string","description":"ID of the reaction"}}},"description":"Emoji reactions to it"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"}}},"description":"The messages before it, the message itself, then the messages after it, oldest first. Keys only some messages carry appear only when set: replyTo (the quoted message, filled in with its sender and files), replyToMediaId, replyToChat and replyToChatName, threadRoot and alsoInChannel (a thread reply), threadReplyCount, threadLastReplyAt, threadParticipants, threadTitle, threadTitleBy, threadTitleAt and threadStart (a thread's root), location, linkPreview, card (a bot's Kazee Card with its public state, plus your own answer as card.mine), forwardedFrom, storyRef, systemData, editedAt, deletedAt and findMeCode"},"anchorIndex":{"type":"integer","description":"Position of the message asked for (or its thread's root) in messages, counting from 0"},"hasMoreBefore":{"type":"boolean","description":"Whether older messages exist before the first one returned"},"hasMoreAfter":{"type":"boolean","description":"Whether newer messages exist after the last one returned"},"unreadCount":{"type":"integer","description":"How many messages in the chat you have not read (thread replies that stay in their thread are counted per thread instead)"},"oldestUnreadMessageId":{"type":"string","description":"ID of the oldest of those; null when there are none"},"thread":{"type":"object","properties":{"rootId":{"type":"string","description":"ID of the thread's root"},"replyId":{"type":"string","description":"ID of the reply asked for"}},"description":"Only when threads is true and the message asked for is a reply that stays in its thread: the timeline is centred on its root, and the app opens the thread on top at the reply"}},"description":"The messages around the one asked for"}}},"example":{"success":true,"data":{"messages":[{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","status":"delivered","type":"image","interactive":{"buttons":[]},"medias":[{"_id":"6ad1d0d4e5f6a7b8c9dae101","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":"66f1b2c3d4e5f60718293a4b","messageId":"6ad1d0b2c3d4e5f6a7b8c901","url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"image","bucketName":"org-66a4b275003d1b495212b5aa","fileName":"delivery-note-october.jpg","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg","thumbHash":"1QcSHQRnh493V4dIh4eXh1h4kJUI","width":1600,"height":1200,"thumbnail":{"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg","bucketName":"org-66a4b275003d1b495212b5aa","width":640,"height":480},"createdAt":"2026-10-16T05:12:01.000Z","updatedAt":"2026-10-16T05:12:03.000Z","__v":0}],"viewedBy":["66f1b2c3d4e5f60718293a5c"],"mentions":["66f1b2c3d4e5f60718293a5c"],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","emoji":"👍","createdAt":"2026-10-16T05:14:40.000Z","_id":"6ad1d0f7b8c9daebfc0d1e01"}],"timestamp":"2026-10-16T05:12:03.000Z","createdAt":"2026-10-16T05:12:03.000Z","updatedAt":"2026-10-16T05:14:40.000Z","__v":0},{"_id":"6ad1d0b2c3d4e5f6a7b8c902","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"The October invoices went out this morning.","status":"delivered","type":"text","interactive":{"buttons":[]},"medias":[],"viewedBy":["66f1b2c3d4e5f60718293a5c"],"mentions":[],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[],"timestamp":"2026-10-16T05:31:09.000Z","createdAt":"2026-10-16T05:31:09.000Z","updatedAt":"2026-10-16T05:31:09.000Z","__v":0}],"anchorIndex":0,"hasMoreBefore":false,"hasMoreAfter":true,"unreadCount":1,"oldestUnreadMessageId":"6ad1d0b2c3d4e5f6a7b8c901","thread":{"rootId":"6ad1d0b2c3d4e5f6a7b8c901","replyId":"6ad1d0b2c3d4e5f6a7b8c903"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of (code chat-not-found), or no message with anchorMessageId in it (code anchor-not-found); the reply also carries that code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"chatId or anchorMessageId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/messages/{chatId}/{userId}/by-date":{"get":{"tags":["Messages"],"summary":"Find a chat's first message on a date","description":"Finds the message to jump to for a date in a chat you are a member of, then load it with getMessagesAround. With tz, it is the first message of that local day; without, the first message at or after midnight UTC of that date, even if days later. If there is none, it is the last message before that day; found is false when there is neither.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getMessagesByDate","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"date","in":"query","required":true,"schema":{"type":"string"},"description":"The day: YYYY-MM-DD with tz; without tz, YYYY-MM-DD or a full ISO 8601 date and time (only its UTC day counts)","example":"2026-10-16"},{"name":"threads","in":"query","required":false,"schema":{"type":"boolean"},"description":"true (or 1) to land only on messages the chat shows, never on a reply that stays in its thread","example":true},{"name":"tz","in":"query","required":false,"schema":{"type":"string"},"description":"Your time zone, as a name (Africa/Nairobi) or an offset (+03:00), so the day is your local day","example":"Africa/Nairobi"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked, even when nothing was found"},"data":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the message; null when the chat has none to offer"},"createdAt":{"type":"string","format":"date-time","description":"When it was sent; null when nothing was found"},"found":{"type":"boolean","description":"Whether a message was found"}},"description":"The message to jump to"}}},"example":{"success":true,"data":{"messageId":"6ad1d0b2c3d4e5f6a7b8c901","createdAt":"2026-10-16T05:12:03.000Z","found":true}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No chat with that ID that you are a member of, chatId is not a valid ID, or date (with tz) is not a valid date","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/user/list":{"get":{"tags":["People"],"summary":"List people","description":"Lists everyone in your organisation in one go, with no paging: people and bots, but not outside systems' app logins, and not other people's personal bots (a personal bot is listed to its owner only). Each comes with contact details, whether they are online and a link to their profile photo. People whose account has been turned off are listed too, and nothing in the reply marks them.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"listUsers","responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"users":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"User ID"},"name":{"type":"string","description":"Full name"},"email":{"type":"string","description":"Email address; absent if they have none"},"phone":{"type":"string","description":"Phone number; absent if they have none"},"role":{"type":"string","description":"Their role in the organisation, as Kazee sign-in names it"},"type":{"type":"string","description":"Human for a person, AI for a bot"},"pbxExtension":{"type":"string","description":"Their office phone extension, if they have one"},"profilePhoto":{"type":"string","description":"Link to their full-size profile photo, valid 7 days; null if they have none"},"online":{"type":"boolean","description":"Whether they are connected to Chat right now"},"lastSeen":{"type":"string","format":"date-time","description":"When they were last connected; null if never"}}},"description":"Everyone in your organisation, people and bots, in no set order; fields a person does not have are left out"}}},"example":{"success":true,"users":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina.wanjiru@example.com","phone":"+254712345678","role":"Member","type":"Human","pbxExtension":"214","profilePhoto":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","online":true,"lastSeen":"2026-10-16T06:12:40.000Z"},{"_id":"6ad1d0f6a7b8c9daebfc0301","name":"Maya","role":"Member","type":"AI","profilePhoto":null,"online":false,"lastSeen":null}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]}},"/user/{userId}":{"get":{"tags":["People"],"summary":"Get a person","description":"Gets one person in your organisation: name, role, whether they finished Chat's welcome, and a link to their profile photo. online and lastSeen are always false and null at present; use getUserOnlineStatus for those.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the person","example":"66f1b2c3d4e5f60718293a5c"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"user":{"type":"object","properties":{"_id":{"type":"string","description":"User ID"},"name":{"type":"string","description":"Full name"},"onboarded":{"type":"boolean","description":"Whether they have finished Chat's first-run welcome"},"role":{"type":"string","description":"Their role in the organisation, as Kazee sign-in names it"},"online":{"type":"boolean","description":"Always false at present: this call does not read who is online (use getUserOnlineStatus)"},"lastSeen":{"description":"Always null at present, for the same reason"},"profilePhoto":{"type":"string","description":"Link to their full-size profile photo, valid 7 days; null if they have none"}},"description":"The person"}}},"example":{"success":true,"user":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","onboarded":true,"role":"Member","online":false,"lastSeen":null,"profilePhoto":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a5c/brian-2026-09-11_14-02-31.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"description":"More than 240 calls in a minute with the same sign-in for the same person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"No person with that ID, or userId is not a valid ID; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]},"put":{"tags":["People"],"summary":"Set my welcome status","description":"Sets whether you have finished Chat's first-run welcome; it is the only thing this call changes. You can only change your own record, and the reply is your whole record.\n\n**Permission:** `chat.users.update` (Update own profile).","operationId":"updateUser","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"onboarded":{"type":"boolean","description":"true once you have finished the welcome; false to see it again","examples":[true]}},"required":["onboarded"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"user":{"type":"object","properties":{"_id":{"type":"string","description":"User ID"},"name":{"type":"string","description":"Full name"},"email":{"type":"string","description":"Email address"},"phone":{"type":"string","description":"Phone number"},"organizationId":{"type":"string","description":"ID of your organisation"},"role":{"type":"string","description":"Your role in the organisation, as Kazee sign-in names it"},"type":{"type":"string","description":"Human for a person, AI for a bot"},"onboarded":{"type":"boolean","description":"Whether you have finished Chat's first-run welcome"},"pbxExtension":{"type":"string","description":"Your office phone extension, if you have one"},"zohoId":{"type":"string","description":"Your ID in Zoho, if you are linked to it"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string","description":"Where the full photo is stored"},"bucketName":{"type":"string","description":"Which store holds it"},"thumbMinioPath":{"type":"string","description":"Where the 256-pixel version is stored; absent on older photos"},"thumbBucketName":{"type":"string","description":"Which store holds the 256-pixel version"}},"description":"Where your profile photo is stored (not a link; getUser gives the link)"},"commands":{"type":"array","description":"Slash commands a bot offers; always empty for a person"},"createdAt":{"type":"string","format":"date-time","description":"When Chat first saw you"},"updatedAt":{"type":"string","format":"date-time","description":"When your record last changed"},"__v":{"type":"integer","description":"Internal version counter"}},"description":"Your whole record after the change"}}},"example":{"success":true,"user":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina.wanjiru@example.com","phone":"+254712345678","organizationId":"66a4b275003d1b495212b5aa","role":"Member","type":"Human","onboarded":true,"pbxExtension":"214","zohoId":"4876000000123001","profilePhoto":{"minioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"commands":[],"createdAt":"2026-03-04T07:30:00.000Z","updatedAt":"2026-10-16T06:15:00.000Z","__v":0}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"onboarded cannot be read as true or false, or your record is not in Chat; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.update"]}],"x-required-scopes":["chat.users.update"]}},"/user/{userId}/online-status":{"get":{"tags":["People"],"summary":"Check whether a person is online","description":"Tells you whether one person is connected to Chat right now and when they were last seen. A person Chat has never seen connect answers online false and lastSeen null, so an unknown ID does too.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getUserOnlineStatus","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the person","example":"66f1b2c3d4e5f60718293a5c"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"online":{"type":"boolean","description":"Whether they are connected to Chat right now"},"lastSeen":{"type":"string","format":"date-time","description":"When they were last connected; null if Chat has never seen them"}}},"example":{"success":true,"online":true,"lastSeen":"2026-10-16T06:12:40.000Z"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"userId is not a valid ID; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]}},"/user/online-status/all":{"get":{"tags":["People"],"summary":"List who is online","description":"Lists everyone in your organisation who has ever connected to Chat, with whether they are online now, when they were last seen and whether they are on a call. The answer may be up to 5 seconds old; changes as they happen arrive over the live connection.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getAllUsersOnlineStatus","responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"onlineStatuses":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"User ID"},"online":{"type":"boolean","description":"Whether they are connected to Chat right now"},"lastSeen":{"type":"string","format":"date-time","description":"When they were last connected"},"inCall":{"type":"boolean","description":"Whether they are on a call or in a meeting right now"},"inCallKind":{"type":"string","description":"internal (a Kazee call, a meeting or an office extension) or external (an outside phone number) while inCall; null otherwise"}}},"description":"One entry for everyone in your organisation Chat has seen connect; people never seen are left out"}}},"example":{"success":true,"onlineStatuses":[{"userId":"66f1b2c3d4e5f60718293a5c","online":true,"lastSeen":"2026-10-16T06:12:40.000Z","inCall":true,"inCallKind":"external"},{"userId":"66f1b2c3d4e5f60718293a4b","online":false,"lastSeen":"2026-10-16T05:58:03.000Z","inCall":false,"inCallKind":null}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]}},"/user/{userId}/preferences/{chatId}":{"get":{"tags":["Settings"],"summary":"Get my settings for a chat","description":"Gets your own settings for one chat: whether it sends you phone notifications and its background picture. It does not look the chat up, so any chat ID answers, with the defaults (notifications on, no background) if you never changed them.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getUserPreference","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"preferences":{"type":"object","properties":{"chatId":{"type":"string","description":"The chat these settings are for"},"notification":{"type":"boolean","description":"Whether the chat sends you phone notifications; true unless you turned them off"},"wallpaper":{"description":"Link to the chat's background picture; null if none is set"}},"description":"Your settings for the chat"}}},"example":{"success":true,"preferences":{"chatId":"6ad1d0a1c2b3a4f5e6d7c801","notification":true,"wallpaper":null}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]}},"/user/{userId}/mute/all":{"get":{"tags":["Settings"],"summary":"List all my mutes","description":"Gets all your mutes at once: the mute on all notifications and each chat you have muted, with when each ends.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getAllMuteStatus","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"globalMute":{"type":"object","properties":{"isGlobalMuted":{"type":"boolean","description":"Whether all your notifications are muted right now"},"muteUntil":{"description":"When the mute ends by itself; null when not muted"},"allowMentions":{"type":"boolean","description":"Whether @mentions of you still notify you while muted; true when not muted"}},"description":"Your mute on all notifications"},"mutedChats":{"type":"object","properties":{"6ad1d0a1c2b3a4f5e6d7c801":{"type":"object","properties":{"muteUntil":{"type":"string","format":"date-time","description":"When that chat's mute ends by itself"}},"description":"One muted chat (the key is its ID)"},"6ad1d0a1c2b3a4f5e6d7c802":{"type":"object","properties":{"muteUntil":{"type":"string","format":"date-time"}}}},"description":"The chats you have muted right now, keyed by chat ID; empty when none"}}},"example":{"success":true,"globalMute":{"isGlobalMuted":false,"muteUntil":null,"allowMentions":true},"mutedChats":{"6ad1d0a1c2b3a4f5e6d7c801":{"muteUntil":"2026-10-16T14:00:00.000Z"},"6ad1d0a1c2b3a4f5e6d7c802":{"muteUntil":"2026-10-23T06:00:00.000Z"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]}},"/user/{userId}/mute/global":{"get":{"tags":["Settings"],"summary":"Check whether all my notifications are muted","description":"Tells you whether you have muted all your notifications, until when, and whether @mentions still come through.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getGlobalMuteStatus","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"isGlobalMuted":{"type":"boolean","description":"Whether all your notifications are muted right now"},"muteUntil":{"type":"string","format":"date-time","description":"When the mute ends by itself; null when not muted"},"allowMentions":{"type":"boolean","description":"Whether @mentions of you still notify you while muted; true when not muted"}}},"example":{"success":true,"isGlobalMuted":true,"muteUntil":"2026-10-16T09:00:00.000Z","allowMentions":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]},"post":{"tags":["Settings"],"summary":"Mute all my notifications","description":"Mutes every phone notification for you for a while, or ends the mute. While muted, @mentions of you still come through unless allowMentions is false. The mute ends by itself after duration; leaving duration out (or a JSON 0) ends it now. A new call replaces the previous mute.\n\n**Permission:** `chat.users.update` (Update own profile).","operationId":"setGlobalMute","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"allowMentions":{"type":"boolean","default":true,"description":"Whether @mentions of you still notify you while muted. Defaults to true. Must be a JSON true or false. Ending the mute sets it back to true","examples":[true]},"duration":{"type":"integer","minimum":0,"description":"How long to mute, in milliseconds, e.g. 3600000 for an hour. Leave it out, or send null or a JSON 0, to end the mute. Send a number: the text \"0\" mutes with no end","examples":[3600000]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"Global mute enabled, or Global mute disabled"},"isGlobalMuted":{"type":"boolean","description":"Whether all your notifications are muted right now"},"muteUntil":{"type":"string","format":"date-time","description":"When the mute ends by itself; null when not muted"},"allowMentions":{"type":"boolean","description":"Whether @mentions of you still notify you while muted; true when not muted"}}},"example":{"success":true,"message":"Global mute enabled","isGlobalMuted":true,"muteUntil":"2026-10-16T09:00:00.000Z","allowMentions":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"duration is not a number of milliseconds of 0 or more, or allowMentions is not a JSON true or false; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.update"]}],"x-required-scopes":["chat.users.update"]}},"/user/{userId}/mute/chat/{chatId}":{"get":{"tags":["Settings"],"summary":"Check whether I muted a chat","description":"Tells you whether you have muted one chat and until when. It does not look the chat up, so an unknown chat ID answers not muted.\n\n**Permission:** `chat.chats.read` (Read chats).","operationId":"getChatMuteStatus","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"chatId":{"type":"string","description":"The chat"},"isMuted":{"type":"boolean","description":"Whether you have muted it right now"},"muteUntil":{"type":"string","format":"date-time","description":"When the mute ends by itself; null when not muted"}}},"example":{"success":true,"chatId":"6ad1d0a1c2b3a4f5e6d7c801","isMuted":true,"muteUntil":"2026-10-16T14:00:00.000Z"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.read"]}],"x-required-scopes":["chat.chats.read"]},"post":{"tags":["Settings"],"summary":"Mute a chat","description":"Stops phone notifications from one chat for you for a while, or unmutes it. The mute ends by itself after duration; leaving duration out (or a JSON 0) unmutes now. A new call replaces the previous mute. It does not look the chat up or check you are in it.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"muteChat","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"duration":{"type":"integer","minimum":0,"description":"How long to mute, in milliseconds, e.g. 28800000 for 8 hours. Leave it out, or send null or a JSON 0, to unmute. Send a number: the text \"0\" mutes the chat with no end","examples":[28800000]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"Chat muted successfully, or Chat unmuted successfully"},"chatId":{"type":"string","description":"The chat"},"muteUntil":{"type":"string","format":"date-time","description":"When the mute ends by itself; null after unmuting"},"isMuted":{"type":"boolean","description":"Whether the chat is muted now"}}},"example":{"success":true,"message":"Chat muted successfully","chatId":"6ad1d0a1c2b3a4f5e6d7c801","muteUntil":"2026-10-16T14:00:00.000Z","isMuted":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"duration is not a number of milliseconds of 0 or more; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/bot/{botId}/commands":{"get":{"tags":["Bots"],"summary":"List a bot's commands","description":"Lists the slash commands a bot offers, for the / menu in a chat with it. It looks the ID up among everyone in the organisation, so a person's ID answers an empty list.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getBotCommands","parameters":[{"name":"botId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the bot","example":"6ad1d0f6a7b8c9daebfc0301"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"botId":{"type":"string","description":"The bot ID you asked about, as you sent it"},"commands":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The command, without the leading /"},"description":{"type":"string","description":"What it does; empty when none was given"},"args":{"type":"string","description":"What to type after it, as a hint; empty when none"}}},"description":"The slash commands it offers, in the order it registered them"}}},"example":{"success":true,"botId":"6ad1d0f6a7b8c9daebfc0301","commands":[{"name":"invoice","description":"Find an invoice by its number","args":"<number>"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No one in the organisation has that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"botId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]},"put":{"tags":["Bots"],"summary":"Set my bot's commands","description":"Replaces the whole list of slash commands a bot offers in the / menu. Only the bot itself may call it, with its own bot token; there is no separate permission. Entries without a name are dropped, and anything that is not a list (JSON text of a list included) clears every command.\n\n**Permission:** any signed-in member.","operationId":"setBotCommands","parameters":[{"name":"botId","in":"path","required":true,"schema":{"type":"string"},"description":"The bot's own ID","example":"6ad1d0f6a7b8c9daebfc0301"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"commands":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The command; a leading / is removed"},"description":{"type":"string","description":"What it does"},"args":{"type":"string","description":"What to type after it, as a hint"}},"required":["name"]},"description":"Every command the bot offers, sent in full each time; an empty list clears them","examples":[[{"name":"invoice","description":"Find an invoice by its number","args":"<number>"}]]}},"required":["commands"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"botId":{"type":"string","description":"The bot's ID"},"commands":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"The command, without the leading /"},"description":{"type":"string","description":"What it does; empty when none was given"},"args":{"type":"string","description":"What to type after it, as a hint; empty when none"}}},"description":"The commands now offered"}}},"example":{"success":true,"botId":"6ad1d0f6a7b8c9daebfc0301","commands":[{"name":"invoice","description":"Find an invoice by its number","args":"<number>"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Only the bot itself may set its commands, signed in with its own bot token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No one in the organisation has that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":[]}]}},"/bot/{botId}/apps":{"get":{"tags":["Bots"],"summary":"List a bot's apps","description":"Lists the apps a bot offers in its direct chats, for the chat's Apps button: each app's key, title and icon, never its address. An unknown ID, a person's ID or a bot with no apps all answer an empty list.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getBotApps","parameters":[{"name":"botId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the bot","example":"6ad1d0f6a7b8c9daebfc0301"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"botId":{"type":"string","description":"The bot ID you asked about, as you sent it"},"apps":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"The app's key, for launchBotApp and a card's open button"},"title":{"type":"string","description":"Its name on the Apps button"},"icon":{"type":"string","description":"A lucide icon name; absent when none was given"}}},"description":"The apps it offers, in the order it registered them"}}},"example":{"success":true,"botId":"6ad1d0f6a7b8c9daebfc0301","apps":[{"key":"browser","title":"Browser","icon":"globe"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]},"put":{"tags":["Bots"],"summary":"Set my bot's apps","description":"Replaces the whole list of apps a bot offers in its direct chats (the Apps button, and open buttons on its cards). Only the bot itself may call it, with its own bot token; there is no separate permission. Any bad entry refuses the whole list, and an empty list removes every app.\n\n**Permission:** any signed-in member.","operationId":"setBotApps","parameters":[{"name":"botId","in":"path","required":true,"schema":{"type":"string"},"description":"The bot's own ID","example":"6ad1d0f6a7b8c9daebfc0301"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"apps":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"1 to 32 lowercase letters, digits or -, starting with a letter; each key once"},"title":{"type":"string","description":"Name on the Apps button, 1 to 40 characters"},"url":{"type":"string","description":"The app's page: an https:// address of up to 2048 characters on an address this Chat allows for bot apps (by default https://api.agentspace.kazee.africa), with no user name, password or #part"},"icon":{"type":"string","description":"Optional lucide icon name, 1 to 32 lowercase letters, digits or -"}},"required":["key","title","url"]},"description":"Every app the bot offers, at most 8 (JSON text of the list also works). Sent in full each time","examples":[[{"key":"browser","title":"Browser","icon":"globe","url":"https://api.agentspace.kazee.africa/api/apps/browser"}]]}},"required":["apps"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"botId":{"type":"string","description":"The bot's ID"},"apps":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"The app's key, for launchBotApp and a card's open button"},"title":{"type":"string","description":"Its name on the Apps button"},"icon":{"type":"string","description":"A lucide icon name; absent when none was given"}}},"description":"The apps now offered, without their addresses"}}},"example":{"success":true,"botId":"6ad1d0f6a7b8c9daebfc0301","apps":[{"key":"browser","title":"Browser","icon":"globe"}]}}}},"400":{"description":"apps is not a list (or JSON text of one), has over 8 entries, or an entry is wrong; the error names the entry and what is wrong with it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Only the bot itself may set its apps, signed in with its own bot token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No one in the organisation has that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Bot apps are switched off on this server (its list of allowed app addresses is not valid)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":[]}]}},"/media/{mediaId}":{"get":{"tags":["Media & files"],"summary":"Get a file's download link","description":"Makes a fresh download address for a chat file, valid for 7 days. You must be a member of the file's chat (or have uploaded it).\n\n**Permission:** `chat.media.read` (Download media).","operationId":"downloadMedia","parameters":[{"name":"mediaId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the file","example":"6ad1d0d4e5f6a7b8c9dae101"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"url":{"type":"string","description":"Address to download the file, valid for 7 days"},"media":{"type":"object","properties":{"_id":{"type":"string","description":"File ID"},"type":{"type":"string","description":"image, video, location or file"},"fileName":{"type":"string","description":"Name of the file as it was uploaded"},"minioPath":{"type":"string","description":"Where it is stored"}},"description":"The file"}}},"example":{"success":true,"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-2026-10-16_09-20-00.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","media":{"_id":"6ad1d0d4e5f6a7b8c9dae101","type":"image","fileName":"site-visit.jpg","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-2026-10-16_09-20-00.jpg"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No file with that ID or it is in a chat you are not in, mediaId is not a valid ID, or the link could not be made","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.media.read"]}],"x-required-scopes":["chat.media.read"]}},"/media/{mediaId}/document-session":{"get":{"tags":["Media & files"],"summary":"Open a chat file for editing","description":"Opens a chat file (a Word, Excel, PowerPoint or other office document) in the document editor in the browser. Only members of the file's chat may open it. Saving in edit mode overwrites the file in the chat for everyone.\n\n**Permission:** `chat.docs.read` (Open documents).","operationId":"getDocumentSession","parameters":[{"name":"mediaId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat file","example":"6ad1d0d4e5f6a7b8c9dae101"},{"name":"mode","in":"query","required":false,"schema":{"type":"string","enum":["edit","view"],"default":"edit"},"description":"view opens it read-only; anything else opens it for editing","example":"view"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"session":{"type":"object","properties":{"iframeUrl":{"type":"string","description":"Address to load in a frame (an <iframe src>) to show the editor, with the access token in it"},"accessToken":{"type":"string","description":"The access token on its own, valid for one hour, for a form post instead"},"accessTokenExpiresAt":{"type":"integer","description":"When the access token stops working, in milliseconds since 1970"},"wopiSrc":{"type":"string","description":"Address the editor reads and saves the file through"},"editorUrl":{"type":"string","description":"Address of the editor for this kind of file"}},"description":"How to open the file in the document editor"}}},"example":{"success":true,"session":{"iframeUrl":"https://office.kazee.africa/browser/0b27e85/cool.html?WOPISrc=https%3A%2F%2Fchat.inet.africa%2Fapi%2Fwopi%2Ffiles%2F6ad1d0d4e5f6a7b8c9dae101&access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmaWQiOiI2YWQxZDBkNGU1ZjZhN2I4YzlkYWUxMDEiLCJwZXJtcyI6WyJ2aWV3Il19.4q9cTz0YH8mJk2sV1eXbN3rPw7uLa6dGf5hQ0iKoM2c&access_token_ttl=1792148400000&permission=readonly","accessToken":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmaWQiOiI2YWQxZDBkNGU1ZjZhN2I4YzlkYWUxMDEiLCJwZXJtcyI6WyJ2aWV3Il19.4q9cTz0YH8mJk2sV1eXbN3rPw7uLa6dGf5hQ0iKoM2c","accessTokenExpiresAt":1792148400000,"wopiSrc":"https://chat.inet.africa/api/wopi/files/6ad1d0d4e5f6a7b8c9dae101","editorUrl":"https://office.kazee.africa/browser/0b27e85/cool.html?"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"mediaId is not a valid ID, no file has that ID, you are not a member of its chat, the editor is not set up, or the editor cannot open this kind of file","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.docs.read"]}],"x-required-scopes":["chat.docs.read"]}},"/media/{mediaId}/readable":{"get":{"tags":["Media & files"],"summary":"Read a chat file in the app","description":"Gives a link to read a chat file inside the app: a PDF as it is, or a PDF copy of a Word, Excel or PowerPoint file, made the first time anyone reads it. Only members of the file's chat may read it. Nothing here can change the file; editing is getDocumentSession.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getReadableMedia","parameters":[{"name":"mediaId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat file","example":"6ad1d0d4e5f6a7b8c9dae101"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"url":{"type":"string","description":"Short-lived link to a PDF of the file, for a plain read-only page viewer"},"expiresInSeconds":{"type":"integer","description":"How long the link works"},"converted":{"type":"boolean","description":"true when the PDF is a copy made from an office file, false when the file is itself a PDF"}}},"example":{"success":true,"url":"https://blobstore.example/chat/report-readable.pdf?X-Amz-Signature=...","expiresInSeconds":3600,"converted":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"mediaId is not a valid ID, no file has that ID, you are not a member of its chat, the file is not a PDF or office file (unsupported), it is over 25 MB (too_large), or it could not be turned into a PDF (convert_failed)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/chat/{chatId}/media":{"get":{"tags":["Media & files"],"summary":"List a chat's files","description":"Lists the files sent in a chat, newest first, a page at a time, each with a fresh download address valid for 7 days, plus how many files of each type the chat has. You must be a member of the chat.\n\n**Permission:** `chat.media.read` (Download media).","operationId":"listMedia","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":10},"description":"Files per page","example":20},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1},"description":"Page number, from 1","example":2},{"name":"type","in":"query","required":false,"schema":{"type":"string"},"description":"Only files of this type: image, video or file, or a comma-separated list of them such as image,video. Leave out for all three","example":"image,video"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"data":{"type":"object","properties":{"media":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"File ID"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it was uploaded to"},"url":{"type":"string","description":"Address to download it, valid for 7 days"},"type":{"type":"string","description":"image, video or file (anything that is not a picture or video, voice notes included)"},"bucketName":{"type":"string","description":"Which store holds it"},"fileName":{"type":"string","description":"Name of the file as it was uploaded"},"minioPath":{"type":"string","description":"Where it is stored: chat/<chat ID>/<name>-<upload time>.<extension>"},"thumbHash":{"type":"string","description":"The small blurred placeholder the sender sent; absent when none was sent"},"width":{"type":"integer","description":"Width in pixels the sender sent; absent when none was sent"},"height":{"type":"integer","description":"Height in pixels the sender sent; absent when none was sent"},"thumbnail":{"type":"object","properties":{"url":{"type":"string","description":"Address to download the preview, valid for 7 days"},"minioPath":{"type":"string","description":"Where the preview is stored"},"bucketName":{"type":"string","description":"Which store holds the preview"},"width":{"type":"integer","description":"Preview width in pixels"},"height":{"type":"integer","description":"Preview height in pixels"}},"description":"Preview made at upload: a JPEG at most 640 pixels on its long side for a picture or office document, the first frame for a video (no width or height then). Absent when none could be made"},"createdAt":{"type":"string","format":"date-time","description":"When it was uploaded"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the person"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}},"description":"Their photo as stored (minioPath and bucketName of the photo, thumbMinioPath and thumbBucketName of its 256-pixel copy), not an address; absent when they have none"},"type":{"type":"string","description":"Human, AI (a bot) or App (an outside system)"}},"description":"The person who uploaded it; absent when the upload did not record one (uploadMedia does not)"},"messageId":{"type":"string","description":"ID of the message that carries it; absent until it is sent in a message"}}},"description":"The files, newest first"},"pagination":{"type":"object","properties":{"currentPage":{"type":"integer","description":"The page you asked for, as you sent it"},"totalPages":{"type":"integer","description":"How many pages there are at this limit"},"totalItems":{"type":"integer","description":"How many items match, over all pages"},"limit":{"type":"integer","description":"Items per page, as you sent it"}},"description":"Where this page sits"},"counts":{"type":"object","properties":{"image":{"type":"integer","description":"Pictures"},"video":{"type":"integer","description":"Videos"},"file":{"type":"integer","description":"Other files, voice notes included"}},"description":"How many files of each type the chat has, whatever type you asked for"}},"description":"The page of files"}}},"example":{"success":true,"data":{"media":[{"_id":"6ad1d0d4e5f6a7b8c9dae101","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-2026-10-16_09-20-00.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","type":"image","bucketName":"org-66a4b275003d1b495212b5aa","fileName":"site-visit.jpg","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-2026-10-16_09-20-00.jpg","thumbHash":"1QcSHQRnh493V4dIh4eXh1h4kJUI","width":3024,"height":4032,"thumbnail":{"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-thumb-2026-10-16_09-20-01.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-thumb-2026-10-16_09-20-01.jpg","bucketName":"org-66a4b275003d1b495212b5aa","width":480,"height":640},"createdAt":"2026-10-16T06:20:01.000Z","updatedAt":"2026-10-16T06:20:03.000Z","__v":0,"sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":{"minioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"type":"Human"},"messageId":"6ad1d0b2c3d4e5f6a7b8c901"}],"pagination":{"currentPage":1,"totalPages":3,"totalItems":27,"limit":10},"counts":{"image":18,"video":4,"file":5}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No chat has that ID or you are not in it, chatId is not a valid ID, or type names something other than image, video or file","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.media.read"]}],"x-required-scopes":["chat.media.read"]}},"/chat/{chatId}/links":{"get":{"tags":["Media & files"],"summary":"List a chat's links","description":"Lists the messages in a chat whose text holds an http:// or https:// address, newest first, a page at a time. A reply also carries the message it answers, with that message's sender. You must be a member of the chat.\n\n**Permission:** `chat.links.read` (Read link previews).","operationId":"listLink","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":10},"description":"Messages per page","example":20},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1},"description":"Page number, from 1","example":2}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"data":{"type":"object","properties":{"messages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the person"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}},"description":"Their photo as stored (minioPath and bucketName of the photo, thumbMinioPath and thumbBucketName of its 256-pixel copy), not an address; absent when they have none"},"type":{"type":"string","description":"Human, AI (a bot) or App (an outside system)"}},"description":"The person who sent it"},"content":{"type":"string","description":"The message text, which holds at least one http:// or https:// address"},"type":{"type":"string","description":"Kind of message, usually text"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have seen it"},"mentions":{"type":"array","description":"IDs of the people it mentions"},"reactions":{"type":"array","description":"Reactions to it"},"linkPreview":{"type":"object","properties":{"url":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"image":{"type":"string"},"domain":{"type":"string"}},"description":"Preview of the first link (url, title, description, image, domain); absent when none was made"},"createdAt":{"type":"string","format":"date-time","description":"When it was sent"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}}},"description":"Messages whose text holds a web address, newest first"},"pagination":{"type":"object","properties":{"currentPage":{"type":"integer","description":"The page you asked for, as you sent it"},"totalPages":{"type":"integer","description":"How many pages there are at this limit"},"totalItems":{"type":"integer","description":"How many items match, over all pages"},"limit":{"type":"integer","description":"Items per page, as you sent it"}},"description":"Where this page sits"}},"description":"The page of messages"}}},"example":{"success":true,"data":{"messages":[{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":{"minioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"type":"Human"},"content":"Here is the tender notice: https://tenders.go.ke/notice/4471","type":"text","viewedBy":["66f1b2c3d4e5f60718293a5c"],"mentions":[],"reactions":[],"linkPreview":{"url":"https://tenders.go.ke/notice/4471","title":"Supply of network equipment, tender 4471","description":"Closing date 30 October 2026.","image":"https://tenders.go.ke/static/og.png","domain":"tenders.go.ke"},"createdAt":"2026-10-15T12:04:00.000Z","updatedAt":"2026-10-15T12:06:30.000Z","__v":0}],"pagination":{"currentPage":1,"totalPages":3,"totalItems":27,"limit":10}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No chat has that ID or you are not in it, or chatId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.links.read"]}],"x-required-scopes":["chat.links.read"]}},"/chat/{chatId}/integrations":{"get":{"tags":["Chats"],"summary":"List a chat's apps","description":"Lists the apps on a chat: outside systems (an accounting system, an alarm, a report script) whose app logins an admin added so they can post there as themselves. Apps are not members. Any member may list them.\n\n**Permission:** `chat.chats.read` (Read chats).","operationId":"listChatIntegrations","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"integrations":{"type":"array","items":{"type":"object","properties":{"integrationId":{"type":"string","description":"ID of the app login in Kazee sign-in (Central)"},"principalId":{"type":"string","description":"The app's user ID in Chat: the sender of what it posts"},"name":{"type":"string","description":"The app's name"},"addedBy":{"type":"string","description":"ID of the admin who added it, or null"},"addedAt":{"type":"string","format":"date-time","description":"When it was added, or null"}}},"description":"The apps on the chat; empty when there are none"}}},"example":{"success":true,"integrations":[{"integrationId":"6ad1d1dae1f2a3b4c5d6e701","principalId":"6ad1d1ebf2a3b4c5d6e7f801","name":"Zoho Books","addedBy":"66f1b2c3d4e5f60718293a4b","addedAt":"2026-10-10T11:00:00.000Z"}]}}}},"400":{"description":"chatId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.read"]}],"x-required-scopes":["chat.chats.read"]},"post":{"tags":["Chats"],"summary":"Add an app to a chat","description":"Adds an app login to a group so the outside system behind it can post there as itself, shown with an app tag. It does not become a member and gets no notifications. Only an admin of the group who is still a member may add one; a chat holds at most 20. Adding one that is already there refreshes its name.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"addChatIntegration","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"integrationId":{"type":"string","description":"ID of the app login, from listAvailableChatIntegrations","examples":["6ad1d1dae1f2a3b4c5d6e701"]}},"required":["integrationId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"integrations":{"type":"array","items":{"type":"object","properties":{"integrationId":{"type":"string","description":"ID of the app login in Kazee sign-in (Central)"},"principalId":{"type":"string","description":"The app's user ID in Chat: the sender of what it posts"},"name":{"type":"string","description":"The app's name"},"addedBy":{"type":"string","description":"ID of the admin who added it, or null"},"addedAt":{"type":"string","format":"date-time","description":"When it was added, or null"}}},"description":"The apps on the chat now"}}},"example":{"success":true,"integrations":[{"integrationId":"6ad1d1dae1f2a3b4c5d6e701","principalId":"6ad1d1ebf2a3b4c5d6e7f801","name":"Zoho Books","addedBy":"66f1b2c3d4e5f60718293a4b","addedAt":"2026-10-10T11:00:00.000Z"}]}}}},"400":{"description":"chatId or integrationId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are not an admin of this group who is still a member, Chat is not installed for your organisation, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of, or no app login with that ID for Chat in your organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Another app manages the chat, it already has 20 apps, the app login is switched off or may not post messages, or its ID belongs to someone else in Chat","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"description":"Kazee sign-in (Central) answered without the app login's user ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Kazee sign-in (Central) could not be reached; try again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/chat/{chatId}/integrations/available":{"get":{"tags":["Chats"],"summary":"List apps I can add to a chat","description":"Lists your organisation's app logins that have access to Chat, as set up in Kazee sign-in (Central), and whether each is already on this chat. Only an admin of the group who is still a member may ask.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"listAvailableChatIntegrations","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"integrations":{"type":"array","items":{"type":"object","properties":{"integrationId":{"type":"string","description":"ID of the app login; pass it to addChatIntegration"},"name":{"type":"string","description":"Its name"},"description":{"type":"string","description":"What it is, as written in Kazee sign-in (Central)"},"enabled":{"type":"boolean","description":"Whether it is switched on; one that is off cannot be added"},"canPost":{"type":"boolean","description":"Whether it may post messages; one that may not cannot be added"},"added":{"type":"boolean","description":"Whether it is already on this chat"}}},"description":"Your organisation's app logins that have access to Chat"}}},"example":{"success":true,"integrations":[{"integrationId":"6ad1d1dae1f2a3b4c5d6e701","name":"Zoho Books","description":"Posts invoice and payment alerts","enabled":true,"canPost":true,"added":true}]}}}},"400":{"description":"chatId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are not an admin of this group who is still a member, Chat is not installed for your organisation, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Kazee sign-in (Central) could not be reached; try again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/chatGroups/{userId}":{"get":{"tags":["Chat folders"],"summary":"List my chat folders","description":"Lists your own folders for sorting your chat list. Each person's folders are their own; nobody else sees them. To see which chat is in which folder, use getUserChatSettings.\n\n**Permission:** `chat.groups.read` (Read chat folders).","operationId":"getChatGroups","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"groups":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Folder ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"userId":{"type":"string","description":"ID of the person who owns the folder"},"name":{"type":"string","description":"Its name, up to 50 characters, unique among your folders"},"color":{"type":"string","description":"Its colour as a hex code"},"icon":{"type":"string","description":"Its icon name, if any, e.g. briefcase"},"order":{"type":"integer","description":"Its position among your folders; lower comes first"},"pinnedChats":{"type":"array","items":{"type":"string"},"description":"IDs of the chats pinned at the top of this folder"},"createdAt":{"type":"string","format":"date-time","description":"When it was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}}},"description":"Your folders, by order and then oldest first; empty when you have none"}}},"example":{"success":true,"groups":[{"_id":"6ad1d1a7b8c9d0e1f2a3b401","organizationId":"66a4b275003d1b495212b5aa","userId":"66f1b2c3d4e5f60718293a4b","name":"Work","color":"#6366f1","icon":"briefcase","order":0,"pinnedChats":["6ad1d0a1c2b3a4f5e6d7c801"],"createdAt":"2026-10-01T07:00:00.000Z","updatedAt":"2026-10-16T09:00:00.000Z","__v":1}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"The folders could not be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.groups.read"]}],"x-required-scopes":["chat.groups.read"]}},"/chatSettings/{userId}":{"get":{"tags":["Chat folders"],"summary":"List which folder each chat is in","description":"Lists, for each chat you have personal settings for, which of your folders it is in. A chat you never put in a folder shows groupId null, or is not listed at all.\n\n**Permission:** `chat.groups.read` (Read chat folders).","operationId":"getUserChatSettings","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"settings":{"type":"array","items":{"type":"object","properties":{"chatId":{"type":"string","description":"Chat ID"},"groupId":{"type":"string","description":"ID of the folder it is in, or null for none"}}},"description":"One entry per chat you have personal settings for"}}},"example":{"success":true,"settings":[{"chatId":"6ad1d0a1c2b3a4f5e6d7c801","groupId":"6ad1d1a7b8c9d0e1f2a3b401"},{"chatId":"6ad1d0a1c2b3a4f5e6d7c802","groupId":null}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"The settings could not be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.groups.read"]}],"x-required-scopes":["chat.groups.read"]}},"/meetings":{"get":{"tags":["Meetings"],"summary":"List my meetings","description":"Lists the scheduled meetings in the group chats you are in that overlap a time window, earliest first, at most 200. Meetings in one-to-one chats are not listed.\n\n**Permission:** `chat.meetings.read` (View meetings).","operationId":"listMeetings","parameters":[{"name":"chatId","in":"query","required":false,"schema":{"type":"string"},"description":"Only meetings in this group chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Start of the window. Defaults to 24 hours ago","example":"2026-10-16T00:00:00.000Z"},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"End of the window, after from and at most 92 days later. Defaults to 30 days from now","example":"2026-11-15T00:00:00.000Z"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"meetings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Meeting ID"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chatId":{"type":"string","description":"ID of the conversation it is held in"},"chat":{"type":"object","properties":{"id":{"type":"string","description":"Conversation ID"},"title":{"type":"string","description":"Its name"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"},"source":{"description":"What made it, e.g. spaces:event for a room made for a calendar event; null for an ordinary chat"},"sourceEntityId":{"description":"ID of that calendar event or space; null for an ordinary chat"}},"description":"That conversation; absent when it could not be read back"},"title":{"type":"string","description":"What the meeting is"},"description":{"type":"string","description":"Longer notes; empty when none"},"callType":{"type":"string","description":"audio or video"},"status":{"type":"string","description":"scheduled, started, ended or cancelled. While its attendees are being brought over from the calendar the meeting also carries readiness: syncing"},"startsAt":{"type":"string","format":"date-time","description":"When it starts"},"endsAt":{"type":"string","format":"date-time","description":"When it ends"},"timeZone":{"type":"string","description":"IANA time zone it was planned in"},"createdBy":{"type":"string","description":"ID of the organizer"},"participants":{"type":"array","items":{"type":"string"},"description":"IDs of the conversation's members; empty when the conversation could not be read back"},"origin":{"type":"string","description":"chat when it was scheduled in Chat, spaces when it came from the Spaces calendar"},"card":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the card message"},"published":{"type":"boolean","description":"Whether the card has been posted yet"}},"description":"The meeting's card in the conversation"},"guests":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Guest link switched on"},"locked":{"type":"boolean","description":"Guest entry locked: nobody new may ask to join"}},"description":"Whether people from outside may join through a guest link"},"calendarEvent":{"type":"object","properties":{"app":{"type":"string"},"eventId":{"type":"string"},"syncedAt":{"type":"string","format":"date-time"},"state":{"type":"string"}},"description":"The Spaces calendar event it is linked to (app, eventId, syncedAt, state synced or unavailable; one occurrence of a repeating event also has seriesId, originalStartDate and occurrenceId); null when it has none"},"links":{"type":"object","properties":{"web":{"type":"string","description":"Link that opens it in Kazee Chat on the web"},"android":{"type":"string","description":"Link that opens its card in the phone app"}},"description":"Where to open it"},"createdAt":{"type":"string","format":"date-time","description":"When it was scheduled"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"}}},"description":"The meetings, earliest first, at most 200"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"meetings":[{"id":"6ad1d2a1b2c3d4e5f6a7b801","organizationId":"66a4b275003d1b495212b5aa","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chat":{"id":"6ad1d0a1c2b3a4f5e6d7c801","title":"Finance team","isGroupChat":true,"source":null,"sourceEntityId":null},"title":"October finance review","description":"Go through the October invoices and the cash forecast.","callType":"video","status":"scheduled","startsAt":"2026-10-21T07:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","timeZone":"Africa/Nairobi","createdBy":"66f1b2c3d4e5f60718293a4b","participants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"origin":"chat","card":{"messageId":"6ad1d2a1b2c3d4e5f6a7b801","published":true},"guests":{"enabled":false,"locked":false},"calendarEvent":{"app":"spaces","eventId":"6ad1d2e5f6a7b8c9d0e1f201","syncedAt":"2026-10-16T08:00:04.000Z","state":"synced"},"links":{"web":"https://chat.kazee.africa/?chat=6ad1d0a1c2b3a4f5e6d7c801&meeting=6ad1d2a1b2c3d4e5f6a7b801","android":"kazeechat://chat/6ad1d0a1c2b3a4f5e6d7c801?scrollTo=6ad1d2a1b2c3d4e5f6a7b801"},"createdAt":"2026-10-16T08:00:00.000Z","updatedAt":"2026-10-16T08:00:04.000Z"}],"success":true}}}},"400":{"description":"from or to is not a date, to is not after from, the window is over 92 days, or chatId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Apps cannot list meetings; they read one by its ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.meetings.read"]}],"x-required-scopes":["chat.meetings.read"]},"post":{"tags":["Meetings"],"summary":"Schedule a meeting","description":"Schedules a meeting in a conversation you are in (a group or one-to-one chat) and answers with status 201. Its card is posted in the conversation at once (for one occurrence of a repeating calendar event, from a day before it starts). With the same requestId a retry returns the first meeting instead of making a second. The Spaces calendar schedules for an organizer (createdBy), and without chatId gets a new group chat made for the attendees.\n\n**Permission:** `chat.meetings.create` (Schedule meetings) or `chat.meetings.manage` (Manage meetings (integrations)).","operationId":"createMeeting","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"attendees":{"type":"array","items":{"type":"string"},"description":"Only for the Spaces calendar, calling with its app token: IDs of the people invited (a comma-separated list or JSON text also works). Without chatId they and the organizer become the new room's members; with the chatId of an ordinary chat each must already be in it","examples":[["66f1b2c3d4e5f60718293a5c"]]},"calendarEvent":{"type":"object","description":"Only for the Spaces calendar, calling with its app token: the calendar event it belongs to, { app, eventId } plus seriesId and originalStartDate for one occurrence of a repeating event (JSON text also works)","examples":[{"app":"spaces","eventId":"6ad1d2e5f6a7b8c9d0e1f201"}]},"callType":{"type":"string","enum":["audio","video"],"description":"Kind of call. Defaults to video","examples":["video"]},"chatId":{"type":"string","description":"Conversation to hold it in; you must be in it. Needed from people; the Spaces calendar may leave it out to get a new meeting room","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"createdBy":{"type":"string","description":"Only for the Spaces calendar, calling with its app token: ID of the organizer, a member of the organisation","examples":["66f1b2c3d4e5f60718293a4b"]},"description":{"type":"string","description":"Longer notes, up to 2000 characters","examples":["Go through the October invoices and the cash forecast."]},"endsAt":{"type":"string","format":"date-time","description":"When it ends, in the same exact form; after the start and at most 24 hours later. Defaults to one hour after the start","examples":["2026-10-21T08:00:00.000Z"]},"origin":{"type":"string","enum":["spaces"],"description":"Only for the Spaces calendar, calling with its app token: spaces marks the change as coming from the calendar, so it is not sent back there. A person who sends it is refused","examples":["spaces"]},"requestId":{"type":"string","description":"16 to 128 letters, digits, _ or -, unique to this meeting, so a retry after a lost reply returns the same meeting. Without it each call makes a new meeting","examples":["mtg-2026-10-21-finance-review"]},"startsAt":{"type":"string","format":"date-time","description":"When it starts, written exactly as 2026-10-21T07:00:00.000Z (UTC, with milliseconds). Must be in the future and within a year","examples":["2026-10-21T07:00:00.000Z"]},"timeZone":{"type":"string","description":"IANA time zone it is planned in, e.g. Africa/Nairobi","examples":["Africa/Nairobi"]},"title":{"type":"string","description":"What the meeting is; anything past 120 characters is cut off","examples":["October finance review"]}},"required":["startsAt","timeZone","title"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"meeting":{"type":"object","properties":{"id":{"type":"string","description":"Meeting ID"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chatId":{"type":"string","description":"ID of the conversation it is held in"},"chat":{"type":"object","properties":{"id":{"type":"string","description":"Conversation ID"},"title":{"type":"string","description":"Its name"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"},"source":{"description":"What made it, e.g. spaces:event for a room made for a calendar event; null for an ordinary chat"},"sourceEntityId":{"description":"ID of that calendar event or space; null for an ordinary chat"}},"description":"That conversation; absent when it could not be read back"},"title":{"type":"string","description":"What the meeting is"},"description":{"type":"string","description":"Longer notes; empty when none"},"callType":{"type":"string","description":"audio or video"},"status":{"type":"string","description":"scheduled, started, ended or cancelled. While its attendees are being brought over from the calendar the meeting also carries readiness: syncing"},"startsAt":{"type":"string","format":"date-time","description":"When it starts"},"endsAt":{"type":"string","format":"date-time","description":"When it ends"},"timeZone":{"type":"string","description":"IANA time zone it was planned in"},"createdBy":{"type":"string","description":"ID of the organizer"},"participants":{"type":"array","items":{"type":"string"},"description":"IDs of the conversation's members; empty when the conversation could not be read back"},"origin":{"type":"string","description":"chat when it was scheduled in Chat, spaces when it came from the Spaces calendar"},"card":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the card message"},"published":{"type":"boolean","description":"Whether the card has been posted yet"}},"description":"The meeting's card in the conversation"},"guests":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Guest link switched on"},"locked":{"type":"boolean","description":"Guest entry locked: nobody new may ask to join"}},"description":"Whether people from outside may join through a guest link"},"calendarEvent":{"type":"object","properties":{"app":{"type":"string"},"eventId":{"type":"string"},"syncedAt":{"type":"string","format":"date-time"},"state":{"type":"string"}},"description":"The Spaces calendar event it is linked to (app, eventId, syncedAt, state synced or unavailable; one occurrence of a repeating event also has seriesId, originalStartDate and occurrenceId); null when it has none"},"links":{"type":"object","properties":{"web":{"type":"string","description":"Link that opens it in Kazee Chat on the web"},"android":{"type":"string","description":"Link that opens its card in the phone app"}},"description":"Where to open it"},"createdAt":{"type":"string","format":"date-time","description":"When it was scheduled"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"}},"description":"The meeting"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"meeting":{"id":"6ad1d2a1b2c3d4e5f6a7b801","organizationId":"66a4b275003d1b495212b5aa","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chat":{"id":"6ad1d0a1c2b3a4f5e6d7c801","title":"Finance team","isGroupChat":true,"source":null,"sourceEntityId":null},"title":"October finance review","description":"Go through the October invoices and the cash forecast.","callType":"video","status":"scheduled","startsAt":"2026-10-21T07:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","timeZone":"Africa/Nairobi","createdBy":"66f1b2c3d4e5f60718293a4b","participants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"origin":"chat","card":{"messageId":"6ad1d2a1b2c3d4e5f6a7b801","published":true},"guests":{"enabled":false,"locked":false},"calendarEvent":{"app":"spaces","eventId":"6ad1d2e5f6a7b8c9d0e1f201","syncedAt":"2026-10-16T08:00:04.000Z","state":"synced"},"links":{"web":"https://chat.kazee.africa/?chat=6ad1d0a1c2b3a4f5e6d7c801&meeting=6ad1d2a1b2c3d4e5f6a7b801","android":"kazeechat://chat/6ad1d0a1c2b3a4f5e6d7c801?scrollTo=6ad1d2a1b2c3d4e5f6a7b801"},"createdAt":"2026-10-16T08:00:00.000Z","updatedAt":"2026-10-16T08:00:04.000Z"},"success":true}}}},"400":{"description":"A time, title, time zone, description, callType, requestId, chatId or calendar input is not valid; the start is not in the future or within a year; you are not in the conversation; or requestId was already used for a different meeting","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Only the Spaces calendar may send createdBy, attendees, origin or calendarEvent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The organizer named in createdBy is not in the organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"That calendar occurrence already has a meeting with another organizer or conversation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.meetings.create","chat.meetings.manage"]}],"x-required-scopes":["chat.meetings.create","chat.meetings.manage"],"x-scope-mode":"any"}},"/guest-meetings/{joinCode}":{"get":{"tags":["Meetings"],"summary":"Preview a meeting from a guest link","description":"For someone outside the organisation with a guest link: shows the meeting's title, time and kind, whether guest entry is locked and whether anyone is in the call yet. Needs no sign-in. The reply is never cached.\n\n**Sign-in:** not needed.","operationId":"publicGuestMeeting","parameters":[{"name":"joinCode","in":"path","required":true,"schema":{"type":"string"},"description":"The join code from the guest link (/meet/<join code>), 43 characters","example":"8Eazc9EJr7-wHkb2sc0aAKJWK5C-yBUmKk1-zzGMErE"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"meeting":{"type":"object","properties":{"title":{"type":"string","description":"What the meeting is"},"startsAt":{"type":"string","format":"date-time","description":"When it starts"},"callType":{"type":"string","description":"audio or video"},"locked":{"type":"boolean","description":"true when the host has locked guest entry"},"hostPresent":{"type":"boolean","description":"true while a member is in the meeting's call"}},"description":"What the guest may see of the meeting"}}},"example":{"success":true,"meeting":{"title":"Supplier briefing","startsAt":"2026-10-16T12:00:00.000Z","callType":"video","locked":false,"hostPresent":true}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"description":"No meeting open to guests with that join code: the link is off, or the meeting is cancelled, over, started over 4 hours ago or starts more than 24 hours from now","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"description":"Over 1200 guest calls in a minute from one address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Guest meetings are switched off on this server, or it could not check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/meetings/{meetingId}/guests":{"get":{"tags":["Meetings"],"summary":"See a meeting's guest waiting room","description":"For the meeting's host: shows the guest link and the guests waiting or let in. The host is whoever leads the running call (its host, owner or first member still in it), or the organizer when no call is running.\n\n**Permission:** `chat.meetings.read` (View meetings).","operationId":"hostGuestLobby","parameters":[{"name":"meetingId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the meeting","example":"6ad1d2a1b2c3d4e5f6a7b801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"enabled":{"type":"boolean","description":"Whether the guest link is switched on"},"locked":{"type":"boolean","description":"Whether guest entry is locked"},"joinPath":{"type":"string","description":"Path of the guest link, to put after the Chat web address; null while the link is off"},"hostPresent":{"type":"boolean","description":"true while a member is in the meeting's call"},"guests":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Guest ID, for decideGuestMeeting"},"name":{"type":"string","description":"The name the guest gave"},"state":{"type":"string","description":"waiting, or admitted while they hold a place in the call"}}},"description":"Guests who asked to join and were not turned away, oldest first, at most 50"}}},"example":{"success":true,"enabled":true,"locked":false,"joinPath":"/meet/8Eazc9EJr7-wHkb2sc0aAKJWK5C-yBUmKk1-zzGMErE","hostPresent":true,"guests":[{"id":"6ad1d2c3d4e5f6a7b8c9d001","name":"Joan Achieng","state":"waiting"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are not the meeting's host, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No meeting with that ID in a conversation you are in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Guest meetings are switched off on this server, or it could not check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.meetings.read"]}],"x-required-scopes":["chat.meetings.read"]}},"/meetings/{meetingId}":{"get":{"tags":["Meetings"],"summary":"Get a meeting","description":"Gets one scheduled meeting with its links and what happened in it: whether it was held, when, who came, and how its recordings stand. Open to members of its conversation, and to the Spaces calendar for any meeting in the organisation.\n\n**Permission:** `chat.meetings.read` (View meetings) or `chat.meetings.manage` (Manage meetings (integrations)).","operationId":"getMeeting","parameters":[{"name":"meetingId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the meeting","example":"6ad1d2a1b2c3d4e5f6a7b801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"meeting":{"type":"object","properties":{"outcome":{"type":"object","properties":{"state":{"type":"string","description":"scheduled (still to come), live (someone is in the call), ended or cancelled"},"held":{"type":"boolean","description":"true once anyone was in the call, false when nobody started it; null while it is still to come or when an old meeting's call details are gone"},"startedAt":{"type":"string","format":"date-time","description":"When the call was opened; null when it never was"},"endedAt":{"type":"string","format":"date-time","description":"When the call closed; null while it runs or when it never ran"},"durationSeconds":{"type":"integer","description":"Seconds the call was open; null without both times"},"attended":{"type":"array","items":{"type":"string"},"description":"IDs of the members who joined the call, including those who left"},"guests":{"type":"integer","description":"How many outside guests were let in"},"recordings":{"type":"object","properties":{"total":{"type":"integer","description":"All of them"},"ready":{"type":"integer","description":"Saved and ready to play"},"processing":{"type":"integer","description":"Still recording or being saved"},"failed":{"type":"integer","description":"Failed"}},"description":"The meeting's recordings, counted"}},"description":"What happened: whether it was held, when, who came and its recordings"},"id":{"type":"string","description":"Meeting ID"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chatId":{"type":"string","description":"ID of the conversation it is held in"},"chat":{"type":"object","properties":{"id":{"type":"string","description":"Conversation ID"},"title":{"type":"string","description":"Its name"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"},"source":{"description":"What made it, e.g. spaces:event for a room made for a calendar event; null for an ordinary chat"},"sourceEntityId":{"description":"ID of that calendar event or space; null for an ordinary chat"}},"description":"That conversation; absent when it could not be read back"},"title":{"type":"string","description":"What the meeting is"},"description":{"type":"string","description":"Longer notes; empty when none"},"callType":{"type":"string","description":"audio or video"},"status":{"type":"string","description":"scheduled, started, ended or cancelled. While its attendees are being brought over from the calendar the meeting also carries readiness: syncing"},"startsAt":{"type":"string","format":"date-time","description":"When it starts"},"endsAt":{"type":"string","format":"date-time","description":"When it ends"},"timeZone":{"type":"string","description":"IANA time zone it was planned in"},"createdBy":{"type":"string","description":"ID of the organizer"},"participants":{"type":"array","items":{"type":"string"},"description":"IDs of the conversation's members; empty when the conversation could not be read back"},"origin":{"type":"string","description":"chat when it was scheduled in Chat, spaces when it came from the Spaces calendar"},"card":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the card message"},"published":{"type":"boolean","description":"Whether the card has been posted yet"}},"description":"The meeting's card in the conversation"},"guests":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Guest link switched on"},"locked":{"type":"boolean","description":"Guest entry locked: nobody new may ask to join"}},"description":"Whether people from outside may join through a guest link"},"calendarEvent":{"type":"object","properties":{"app":{"type":"string"},"eventId":{"type":"string"},"syncedAt":{"type":"string","format":"date-time"},"state":{"type":"string"}},"description":"The Spaces calendar event it is linked to (app, eventId, syncedAt, state synced or unavailable; one occurrence of a repeating event also has seriesId, originalStartDate and occurrenceId); null when it has none"},"links":{"type":"object","properties":{"web":{"type":"string","description":"Link that opens it in Kazee Chat on the web"},"android":{"type":"string","description":"Link that opens its card in the phone app"}},"description":"Where to open it"},"createdAt":{"type":"string","format":"date-time","description":"When it was scheduled"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"}},"description":"The meeting"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"meeting":{"outcome":{"state":"ended","held":true,"startedAt":"2026-10-14T07:01:12.000Z","endedAt":"2026-10-14T07:53:12.000Z","durationSeconds":3120,"attended":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"guests":1,"recordings":{"total":1,"ready":1,"processing":0,"failed":0}},"id":"6ad1d2a1b2c3d4e5f6a7b801","organizationId":"66a4b275003d1b495212b5aa","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chat":{"id":"6ad1d0a1c2b3a4f5e6d7c801","title":"Finance team","isGroupChat":true,"source":null,"sourceEntityId":null},"title":"October finance review","description":"Go through the October invoices and the cash forecast.","callType":"video","status":"ended","startsAt":"2026-10-14T07:00:00.000Z","endsAt":"2026-10-14T08:00:00.000Z","timeZone":"Africa/Nairobi","createdBy":"66f1b2c3d4e5f60718293a4b","participants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"origin":"chat","card":{"messageId":"6ad1d2a1b2c3d4e5f6a7b801","published":true},"guests":{"enabled":false,"locked":false},"calendarEvent":{"app":"spaces","eventId":"6ad1d2e5f6a7b8c9d0e1f201","syncedAt":"2026-10-16T08:00:04.000Z","state":"synced"},"links":{"web":"https://chat.kazee.africa/?chat=6ad1d0a1c2b3a4f5e6d7c801&meeting=6ad1d2a1b2c3d4e5f6a7b801","android":"kazeechat://chat/6ad1d0a1c2b3a4f5e6d7c801?scrollTo=6ad1d2a1b2c3d4e5f6a7b801"},"createdAt":"2026-10-16T08:00:00.000Z","updatedAt":"2026-10-14T07:53:40.000Z"},"success":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No meeting with that ID in a conversation you are in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.meetings.read","chat.meetings.manage"]}],"x-required-scopes":["chat.meetings.read","chat.meetings.manage"],"x-scope-mode":"any"},"put":{"tags":["Meetings"],"summary":"Change a meeting","description":"Changes an upcoming meeting's title, notes, time or time zone. Only its organizer may, or the Spaces calendar for any meeting. Moving the start keeps the meeting's length unless endsAt is sent too, and the card in the conversation is updated. Fields left out stay as they are; an empty description removes it.\n\n**Permission:** `chat.meetings.update` (Reschedule meetings) or `chat.meetings.manage` (Manage meetings (integrations)).","operationId":"updateMeeting","parameters":[{"name":"meetingId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the meeting","example":"6ad1d2a1b2c3d4e5f6a7b801"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"attendees":{"type":"array","items":{"type":"string"},"description":"Only for the Spaces calendar, calling with its app token, with origin spaces and calendarRevision: IDs of the people the occurrence is now for","examples":[["66f1b2c3d4e5f60718293a5c"]]},"calendarEvent":{"type":"object","description":"Only for the Spaces calendar, calling with its app token: the calendar event it belongs to, { app, eventId } plus seriesId and originalStartDate for one occurrence of a repeating event (JSON text also works). With createdBy and origin spaces, and no other change, it attaches a calendar occurrence to the meeting","examples":[{"app":"spaces","eventId":"6ad1d2e5f6a7b8c9d0e1f201"}]},"calendarRevision":{"type":"integer","description":"Only for the Spaces calendar, calling with its app token, with origin spaces and occurrenceId: the event's revision, so an older change never overwrites a newer one","examples":[3]},"createdBy":{"type":"string","description":"Only for the Spaces calendar, calling with its app token: the organizer, sent with calendarEvent to attach an occurrence","examples":["66f1b2c3d4e5f60718293a4b"]},"description":{"type":"string","description":"Longer notes, up to 2000 characters","examples":["Go through the October invoices and the cash forecast."]},"endsAt":{"type":"string","format":"date-time","description":"When it ends, in the same exact form; after the start and at most 24 hours later","examples":["2026-10-21T08:00:00.000Z"]},"occurrenceId":{"type":"string","description":"Only for the Spaces calendar, calling with its app token: the occurrence the change is for, <series ID>:<original start>","examples":["6ad1d2e5f6a7b8c9d0e1f201:2026-10-21T07:00:00.000Z"]},"origin":{"type":"string","enum":["spaces"],"description":"Only for the Spaces calendar, calling with its app token: spaces marks the change as coming from the calendar, so it is not sent back there. Ignored from people","examples":["spaces"]},"startsAt":{"type":"string","format":"date-time","description":"When it starts, written exactly as 2026-10-21T07:00:00.000Z (UTC, with milliseconds). Must be in the future and within a year","examples":["2026-10-21T07:00:00.000Z"]},"timeZone":{"type":"string","description":"IANA time zone it is planned in, e.g. Africa/Nairobi","examples":["Africa/Nairobi"]},"title":{"type":"string","description":"What the meeting is, up to 120 characters","examples":["October finance review"]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"meeting":{"type":"object","properties":{"id":{"type":"string","description":"Meeting ID"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chatId":{"type":"string","description":"ID of the conversation it is held in"},"chat":{"type":"object","properties":{"id":{"type":"string","description":"Conversation ID"},"title":{"type":"string","description":"Its name"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"},"source":{"description":"What made it, e.g. spaces:event for a room made for a calendar event; null for an ordinary chat"},"sourceEntityId":{"description":"ID of that calendar event or space; null for an ordinary chat"}},"description":"That conversation; absent when it could not be read back"},"title":{"type":"string","description":"What the meeting is"},"description":{"type":"string","description":"Longer notes; empty when none"},"callType":{"type":"string","description":"audio or video"},"status":{"type":"string","description":"scheduled, started, ended or cancelled. While its attendees are being brought over from the calendar the meeting also carries readiness: syncing"},"startsAt":{"type":"string","format":"date-time","description":"When it starts"},"endsAt":{"type":"string","format":"date-time","description":"When it ends"},"timeZone":{"type":"string","description":"IANA time zone it was planned in"},"createdBy":{"type":"string","description":"ID of the organizer"},"participants":{"type":"array","items":{"type":"string"},"description":"IDs of the conversation's members; empty when the conversation could not be read back"},"origin":{"type":"string","description":"chat when it was scheduled in Chat, spaces when it came from the Spaces calendar"},"card":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the card message"},"published":{"type":"boolean","description":"Whether the card has been posted yet"}},"description":"The meeting's card in the conversation"},"guests":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Guest link switched on"},"locked":{"type":"boolean","description":"Guest entry locked: nobody new may ask to join"}},"description":"Whether people from outside may join through a guest link"},"calendarEvent":{"type":"object","properties":{"app":{"type":"string"},"eventId":{"type":"string"},"syncedAt":{"type":"string","format":"date-time"},"state":{"type":"string"}},"description":"The Spaces calendar event it is linked to (app, eventId, syncedAt, state synced or unavailable; one occurrence of a repeating event also has seriesId, originalStartDate and occurrenceId); null when it has none"},"links":{"type":"object","properties":{"web":{"type":"string","description":"Link that opens it in Kazee Chat on the web"},"android":{"type":"string","description":"Link that opens its card in the phone app"}},"description":"Where to open it"},"createdAt":{"type":"string","format":"date-time","description":"When it was scheduled"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"}},"description":"The meeting"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"meeting":{"id":"6ad1d2a1b2c3d4e5f6a7b801","organizationId":"66a4b275003d1b495212b5aa","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chat":{"id":"6ad1d0a1c2b3a4f5e6d7c801","title":"Finance team","isGroupChat":true,"source":null,"sourceEntityId":null},"title":"October finance review","description":"Go through the October invoices and the cash forecast.","callType":"video","status":"scheduled","startsAt":"2026-10-21T07:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","timeZone":"Africa/Nairobi","createdBy":"66f1b2c3d4e5f60718293a4b","participants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"origin":"chat","card":{"messageId":"6ad1d2a1b2c3d4e5f6a7b801","published":true},"guests":{"enabled":false,"locked":false},"calendarEvent":{"app":"spaces","eventId":"6ad1d2e5f6a7b8c9d0e1f201","syncedAt":"2026-10-16T08:00:04.000Z","state":"synced"},"links":{"web":"https://chat.kazee.africa/?chat=6ad1d0a1c2b3a4f5e6d7c801&meeting=6ad1d2a1b2c3d4e5f6a7b801","android":"kazeechat://chat/6ad1d0a1c2b3a4f5e6d7c801?scrollTo=6ad1d2a1b2c3d4e5f6a7b801"},"createdAt":"2026-10-16T08:00:00.000Z","updatedAt":"2026-10-16T08:00:04.000Z"},"success":true}}}},"400":{"description":"A new value is not valid, the new start is not in the future or within a year, you are not the organizer, the meeting is no longer upcoming, or its attendees are still being synced from the calendar (retry shortly)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Only the Spaces calendar, with origin spaces, may send calendarEvent or createdBy","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No meeting with that ID, or you are no longer in its conversation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The calendar occurrence could not be attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.meetings.update","chat.meetings.manage"]}],"x-required-scopes":["chat.meetings.update","chat.meetings.manage"],"x-scope-mode":"any"}},"/meetings/{chatId}/recordings":{"get":{"tags":["Meetings"],"summary":"List a conversation's recordings","description":"Lists the call recordings made in a conversation you are in, newest first, at most 50: saved ones and ones still recording or being saved. A one-to-one call's recording is listed only for its two people. To play one, use playMeetingRecording.\n\n**Permission:** `chat.media.read` (Download media).","operationId":"meetingRecordings","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the conversation","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"meetingId","in":"query","required":false,"schema":{"type":"string"},"description":"Only recordings of this scheduled meeting, which must belong to the conversation","example":"6ad1d2a1b2c3d4e5f6a7b801"},{"name":"recordingId","in":"query","required":false,"schema":{"type":"string"},"description":"Only this recording","example":"6ad1d2b2c3d4e5f6a7b8c901"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"recordings":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Recording ID"},"directCall":{"type":"boolean","description":"true for a one-to-one call, which only its two people may see"},"chatId":{"type":"string","description":"ID of the conversation the call was in"},"callAttemptId":{"type":"string","description":"ID of the call attempt that was recorded"},"roomId":{"type":"integer","description":"Number of the call's room on the call server"},"status":{"type":"string","description":"starting, recording, stopping, processing (being saved), ready or failed. A failed recording also carries error: why"},"startedBy":{"type":"string","description":"ID of the person who started it"},"startedAt":{"type":"string","format":"date-time","description":"When recording began; absent until it has"},"stoppedAt":{"type":"string","format":"date-time","description":"When recording stopped; absent until it has"},"bytes":{"type":"integer","description":"Size of the saved file in bytes; absent until it is saved"},"duration":{"type":"integer","description":"Length of the saved file in seconds; absent until it is saved"},"meeting":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"calendarEvent":{"type":"object","properties":{"eventId":{"type":"string"}}}},"description":"The scheduled meeting it was made in (id, title, startsAt, and calendarEvent with eventId and, for one occurrence of a repeating event, seriesId and originalStartDate, or null); null for a call that was not a scheduled meeting"}}},"description":"The recordings, newest first, at most 50"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"recordings":[{"id":"6ad1d2b2c3d4e5f6a7b8c901","directCall":false,"chatId":"6ad1d0a1c2b3a4f5e6d7c801","callAttemptId":"ca-7f3a9e15b2d44c8e9f1a2d6b","roomId":48213377,"status":"ready","startedBy":"66f1b2c3d4e5f60718293a4b","startedAt":"2026-10-14T07:05:12.000Z","stoppedAt":"2026-10-14T07:51:40.000Z","bytes":412337152,"duration":2788,"meeting":{"id":"6ad1d2a1b2c3d4e5f6a7b801","title":"October finance review","startsAt":"2026-10-14T07:00:00.000Z","calendarEvent":{"eventId":"6ad1d2e5f6a7b8c9d0e1f201"}}}],"success":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"You are not in the conversation, an ID is not valid, or meetingId is not a meeting of this conversation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.media.read"]}],"x-required-scopes":["chat.media.read"]}},"/call/present/{room}/file":{"get":{"tags":["Meetings"],"summary":"Load the file being presented in a call","description":"Gives someone joined in a call a link to the file being presented in it, whether or not they are in the file's chat, only for as long as it is being presented. Office files come as their PDF copy. There is no download button in the app, but this is a working link for 15 minutes, so someone determined could save the file.\n\n**Permission:** `chat.rtc.read` (Use WebRTC).","operationId":"getCallPresentationFile","parameters":[{"name":"room","in":"path","required":true,"schema":{"type":"string"},"description":"The call room number","example":123456}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"url":{"type":"string","description":"Short-lived link to the file"},"expiresAt":{"type":"integer","description":"When the link stops working, in milliseconds since 1970. Ask again for a new one"},"kind":{"type":"string","description":"video, or pages for a PDF"},"fileName":{"type":"string","description":"Name of the file"}}},"example":{"success":true,"url":"https://blobstore.example/chat/report-readable.pdf?X-Amz-Signature=...","expiresAt":1793838794333,"kind":"pages","fileName":"Q3 launch.pptx"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are not joined in that call, or nothing is being presented in it now (not_available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.rtc.read"]}],"x-required-scopes":["chat.rtc.read"]}},"/org-settings":{"get":{"tags":["Company settings"],"summary":"Read the company's Chat settings","description":"Reads your own company's Chat settings. For your company's admins. A setting that was never saved answers its default.\n\n**Permission:** `chat.settings.admin` (Manage company settings).","operationId":"getOrgSettings","responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"settings":{"type":"object","properties":{"livePresenting":{"type":"boolean","description":"Whether people may start presenting a file in a call. Off until an admin turns it on"}},"description":"The company's Chat settings"}}},"example":{"success":true,"settings":{"livePresenting":false}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You do not hold chat.settings.admin (your company's admins do)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"description":"A setting is not true or false, or nothing to change was sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.settings.admin"]}],"x-required-scopes":["chat.settings.admin"]},"put":{"tags":["Company settings"],"summary":"Change the company's Chat settings","description":"Changes your own company's Chat settings. For your company's admins. Send only what changes. Calls already running pick up a change the next time someone starts presenting.\n\n**Permission:** `chat.settings.admin` (Manage company settings).","operationId":"updateOrgSettings","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"livePresenting":{"type":"boolean","description":"true or false: may people present a file in a call","examples":[true]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"settings":{"type":"object","properties":{"livePresenting":{"type":"boolean","description":"Whether people may start presenting a file in a call. Off until an admin turns it on"}},"description":"The company's Chat settings"}}},"example":{"success":true,"settings":{"livePresenting":true}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You do not hold chat.settings.admin (your company's admins do)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"A setting is not true or false, or nothing to change was sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.settings.admin"]}],"x-required-scopes":["chat.settings.admin"]}},"/meeting-recordings/{recordingId}/playback":{"get":{"tags":["Meetings"],"summary":"Play or download a recording","description":"Gives a private link to a saved call recording (an MP4 file), valid for one hour, to people still in its conversation. A one-to-one call's recording is only for its two people. With download, the link makes the browser save the file instead of playing it.\n\n**Permission:** `chat.media.read` (Download media).","operationId":"playMeetingRecording","parameters":[{"name":"recordingId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the recording","example":"6ad1d2b2c3d4e5f6a7b8c901"},{"name":"download","in":"query","required":false,"schema":{"type":"boolean"},"description":"true (or \"true\" or \"1\") for a link that downloads the file instead of playing it","example":true}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"recording":{"type":"object","properties":{"id":{"type":"string","description":"Recording ID"},"directCall":{"type":"boolean","description":"true for a one-to-one call, which only its two people may see"},"chatId":{"type":"string","description":"ID of the conversation the call was in"},"callAttemptId":{"type":"string","description":"ID of the call attempt that was recorded"},"roomId":{"type":"integer","description":"Number of the call's room on the call server"},"status":{"type":"string","description":"starting, recording, stopping, processing (being saved), ready or failed. A failed recording also carries error: why"},"startedBy":{"type":"string","description":"ID of the person who started it"},"startedAt":{"type":"string","format":"date-time","description":"When recording began; absent until it has"},"stoppedAt":{"type":"string","format":"date-time","description":"When recording stopped; absent until it has"},"bytes":{"type":"integer","description":"Size of the saved file in bytes; absent until it is saved"},"duration":{"type":"integer","description":"Length of the saved file in seconds; absent until it is saved"},"meeting":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"startsAt":{"type":"string","format":"date-time"},"calendarEvent":{"type":"object","properties":{"eventId":{"type":"string"}}}},"description":"The scheduled meeting it was made in (id, title, startsAt, and calendarEvent with eventId and, for one occurrence of a repeating event, seriesId and originalStartDate, or null); null for a call that was not a scheduled meeting"},"url":{"type":"string","description":"Private address of the MP4 file, valid for one hour"},"filename":{"type":"string","description":"Name it downloads as: kazee-meeting (or kazee-call) and the day it was made"},"download":{"type":"boolean","description":"true when the address makes a browser save the file instead of playing it"}},"description":"The recording and its link"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"recording":{"id":"6ad1d2b2c3d4e5f6a7b8c901","directCall":false,"chatId":"6ad1d0a1c2b3a4f5e6d7c801","callAttemptId":"ca-7f3a9e15b2d44c8e9f1a2d6b","roomId":48213377,"status":"ready","startedBy":"66f1b2c3d4e5f60718293a4b","startedAt":"2026-10-14T07:05:12.000Z","stoppedAt":"2026-10-14T07:51:40.000Z","bytes":412337152,"duration":2788,"meeting":{"id":"6ad1d2a1b2c3d4e5f6a7b801","title":"October finance review","startsAt":"2026-10-14T07:00:00.000Z","calendarEvent":{"eventId":"6ad1d2e5f6a7b8c9d0e1f201"}},"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/recordings/6ad1d0a1c2b3a4f5e6d7c801/6ad1d2b2c3d4e5f6a7b8c901/meeting.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=3600&X-Amz-Signature=3f9c2a1b5d7e4c1a","filename":"kazee-meeting-2026-10-14-b8c901.mp4","download":false},"success":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"recordingId is not valid, the recording is not ready (or does not exist), you may not see it or are no longer in its conversation, or its storage does not match the organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.media.read"]}],"x-required-scopes":["chat.media.read"]}},"/webrtc/config":{"get":{"tags":["Calls"],"summary":"Get call connection settings","description":"Gives the call media server's address and relay servers with a user name and password tied to you, valid for an hour by default. Ask again before iceCredentialsExpiresAt. It holds no pass for any one call: each call's room is admitted separately when the call is set up.\n\n**Permission:** `chat.rtc.read` (Use WebRTC).","operationId":"getIceConfig","responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"config":{"type":"object","properties":{"janusServer":{"type":"string","description":"Address of the call media server to connect to"},"roomAdmissionEnabled":{"type":"boolean","description":"true: each call's room must be admitted separately through the call set-up messages"},"callProtocolVersion":{"type":"integer","description":"Version of the call set-up messages to use: 3 with room admission, 2 without"},"iceServers":{"type":"array","items":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string"},"description":"The relay's addresses"},"username":{"type":"string","description":"User name for the relay, tied to you and the time it stops working"},"credential":{"type":"string","description":"Password for the relay"}}},"description":"Relay servers for the call's audio and video, in the form a browser's RTCPeerConnection takes"},"iceCredentialsExpiresAt":{"type":"integer","description":"When the relay user name and password stop working, in milliseconds since 1970"},"plugins":{"type":"object","properties":{"videoroom":{"type":"string","description":"The group room feature"}},"description":"Names of the media server features to use; videoroom for calls"}},"description":"Where and how to connect a call's audio and video"}}},"example":{"success":true,"config":{"janusServer":"wss://calls.kazee.africa/calling/ws","roomAdmissionEnabled":true,"callProtocolVersion":3,"iceServers":[{"urls":["turn:turn.kazee.africa:3478?transport=udp","turn:turn.kazee.africa:3478?transport=tcp","turns:turn.kazee.africa:5349"],"username":"1792144800:2d711642b726b04401627ca9fbac32f5","credential":"XTmQwo0/hABSB74hnmn25E6/kyc="}],"iceCredentialsExpiresAt":1792144800000,"plugins":{"videoroom":"janus.plugin.videoroom"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"description":"Calling is not set up on this server (no media server or relay configured)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.rtc.read"]}],"x-required-scopes":["chat.rtc.read"]}},"/attendance/status":{"get":{"tags":["Attendance"],"summary":"Get my check-in status","description":"Tells you whether you are checked in at work today, as Kazee People (HR Hub) records it; Chat asks on your behalf. Any signed-in person may call it, always for themselves; HR Hub then checks you have attendance access. The answer may be up to a minute old, unless you checked in or out through Chat since.\n\n**Permission:** any signed-in member.","operationId":"attendanceStatus","parameters":[{"name":"timezone","in":"query","required":false,"schema":{"type":"string"},"description":"Your time zone as an IANA name, passed to HR Hub to count your day in; when left out, HR Hub decides","example":"Africa/Nairobi"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"isCheckedIn":{"type":"boolean","description":"Whether you are checked in right now"},"checkInTime":{"type":"string","format":"date-time","description":"When you last checked in today; null if not checked in"},"checkOutTime":{"description":"When you last checked out today; null if you have not"},"firstCheckInTime":{"type":"string","format":"date-time","description":"When you first checked in today; null if you have not"},"totalWorkedMinutes":{"type":"integer","description":"Minutes worked today so far"},"attendanceState":{"type":"string","description":"HR Hub's state for today, e.g. checkedIn or checkedOut"},"timezone":{"type":"string","description":"The time zone the day is counted in; absent if HR Hub gave none"}}},"example":{"success":true,"isCheckedIn":true,"checkInTime":"2026-10-16T05:02:00.000Z","checkOutTime":null,"firstCheckInTime":"2026-10-16T05:02:00.000Z","totalWorkedMinutes":73,"attendanceState":"checkedIn","timezone":"Africa/Nairobi"}}}},"400":{"description":"timezone is not a time zone name such as Africa/Nairobi, or location is not two numbers (code invalid)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are signed in as a bot or an app, not a person (code people_only, or no code for an app token); your account lacks HR Hub attendance access (code no_access); or HR Hub check-in is not set up for your organisation (code not_available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"description":"Too many calls with the same sign-in in a minute (30 for the status, 10 for a check-in or out)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"502":{"description":"HR Hub refused Chat's own request; nothing was recorded (code unavailable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"HR Hub or Kazee sign-in did not answer; for a check-in or out it may or may not have been recorded, so check the status first (code unavailable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":[]}]}},"/mentions/{userId}":{"get":{"tags":["Messages"],"summary":"List messages that mention me","description":"Lists the messages, sent by someone else, that mention you by name or with @all, across all chats. A page is the newest messages, with the unread ones moved to the top. Deleted messages no longer count.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getMentions","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":100,"default":50},"description":"How many to return, at most 100","example":20},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"How many of the newest to skip, for the next page","example":0}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"mentions":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the message"},"content":{"type":"string","description":"Its text, with mentions written @[Name](userId)"},"type":{"type":"string","description":"Its message type"},"createdAt":{"type":"string","format":"date-time","description":"When it was sent"},"isUnread":{"type":"boolean","description":"Whether you have not read it yet"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"chat":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the chat"},"chatName":{"type":"string","description":"The chat's name (a direct chat may have none)"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"}},"description":"The chat it is in"},"threadRoot":{"type":"string","description":"ID of the thread's root when the message is a thread reply (open the thread); absent otherwise"}}},"description":"The page of messages that mention you, sent by others: newest first, then reordered so the unread ones come first"},"total":{"type":"integer","description":"How many messages mention you in all, for paging"}}},"example":{"mentions":[{"_id":"6ad1d0b2c3d4e5f6a7b8c902","content":"Payment from Westlands Mall is in. @[Amina Wanjiru](66f1b2c3d4e5f60718293a4b) please match it to the October invoice.","type":"text","createdAt":"2026-10-16T05:12:03.000Z","isUnread":true,"sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"chat":{"_id":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","isGroupChat":true},"threadRoot":"6ad1d0b2c3d4e5f6a7b8c901"}],"total":7}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/cards/{userId}/waiting":{"get":{"tags":["Messages"],"summary":"List decisions waiting on me","description":"Lists the decision cards waiting on you: ones that name you as a person who must answer, that you have not answered, still open and not past their deadline, in chats you are still in. Cards open to anyone are not listed. With chatId: that chat and its threads; with chatId and threadRootId: only that thread; with neither: all your chats. Oldest first, at most 50; count is the full total.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getWaitingCards","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","example":"66f1b2c3d4e5f60718293a4b"},{"name":"chatId","in":"query","required":false,"schema":{"type":"string"},"description":"Only this chat (and its threads)","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"threadRootId","in":"query","required":false,"schema":{"type":"string"},"description":"Only this thread: ID of its first message. Needs chatId","example":"6ad1d0c3d4e5f6a7b8c9da01"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"count":{"type":"integer","description":"How many decisions wait on you in all, even when more than the list holds"},"decisions":{"type":"array","items":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the card's message"},"chatId":{"type":"string","description":"ID of the chat it is in"},"threadRootId":{"description":"ID of the thread it is in, or null when it is in the chat itself"},"title":{"type":"string","description":"The question"},"senderId":{"type":"string","description":"User ID of the bot or person who sent it"},"senderName":{"type":"string","description":"Their name"},"createdAt":{"type":"string","format":"date-time","description":"When it was sent"},"options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"}}},"description":"The answers to choose from (id and label)"},"recommendation":{"type":"string","description":"ID of the option the sender suggests, or null"}}},"description":"The decisions, oldest first, at most 50"}}},"example":{"success":true,"count":1,"decisions":[{"messageId":"6ad1d0b2c3d4e5f6a7b8c901","chatId":"6ad1d0a1c2b3a4f5e6d7c801","threadRootId":null,"title":"Approve the October fibre invoice?","senderId":"6ad1d0f6a7b8c9daebfc0301","senderName":"Maya","createdAt":"2026-10-16T09:10:00.000Z","options":[{"id":"approve","label":"Approve"},{"id":"reject","label":"Reject"}],"recommendation":"approve"}]}}}},"400":{"description":"threadRootId was sent without chatId, or is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/threads/{userId}/unread":{"get":{"tags":["Threads"],"summary":"Count my unread threads","description":"Counts the threads you follow, have not closed and have unread replies in, across your chats (the Threads badge), looking at your newest 200 followed threads. With detail it also lists them, newest reply first, with enough to name each one.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getThreadsUnread","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"detail","in":"query","required":false,"schema":{"type":"boolean"},"description":"true (or 1) to list the threads too; without it only the count comes back","example":true}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"unreadThreadCount":{"type":"integer","description":"How many followed threads you have not closed have unread replies"},"threads":{"type":"array","items":{"type":"object","properties":{"chatId":{"type":"string","description":"ID of the chat it is in"},"rootId":{"type":"string","description":"ID of the thread's root"},"unreadCount":{"type":"integer","description":"Replies you have not read"},"lastReplyAt":{"type":"string","format":"date-time","description":"When the latest reply came"},"title":{"type":"string","description":"The thread's name, or null"},"root":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the root"},"type":{"type":"string","description":"The root's message type"},"content":{"type":"string","description":"The root's text, cut to 300 characters (a call card is never cut)"},"media":{"description":"ID of an older single file on it, or null"},"medias":{"type":"array","items":{"type":"string"},"description":"IDs of its files"},"isDeleted":{"type":"boolean","description":"Whether the root was deleted (the thread lives on)"},"threadTitle":{"type":"string","description":"The thread's name, or null"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"}},"description":"Who sent the root (_id and name), or null"}},"description":"A small copy of the root to name the thread by, or null if it is gone. It also has pollData.question for a poll and threadStart: true for a thread started on purpose"}}},"description":"Only with detail: those threads, newest reply first"}}},"example":{"success":true,"unreadThreadCount":1,"threads":[{"chatId":"6ad1d0a1c2b3a4f5e6d7c801","rootId":"6ad1d0b2c3d4e5f6a7b8c901","unreadCount":1,"lastReplyAt":"2026-10-16T06:40:12.000Z","title":"October invoice","root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","type":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","media":null,"medias":["6ad1d0d4e5f6a7b8c9dae101"],"isDeleted":false,"threadTitle":"October invoice","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"}}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/threads/{userId}/search":{"get":{"tags":["Threads"],"summary":"Find threads by name","description":"Finds threads in your chats by what q says, for a thread picker: a named thread when every word of q starts a word of its name, an unnamed one when every word starts a word of its root's text, in any case. Newest activity first.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"searchThreads","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":20},"description":"How many threads to return. Defaults to 8, at most 20","example":8},{"name":"q","in":"query","required":true,"schema":{"type":"string"},"description":"Words to look for, at least 2 characters in all (only the first 8 words count)","example":"octo inv"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"data":{"type":"object","properties":{"threads":{"type":"array","items":{"type":"object","properties":{"rootId":{"type":"string","description":"ID of the thread's root"},"chatId":{"type":"string","description":"ID of its chat"},"chatName":{"type":"string","description":"The chat's name; a one-on-one is named by the other person"},"isGroup":{"type":"boolean","description":"Whether the chat is a group"},"root":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the root"},"type":{"type":"string","description":"The root's message type"},"content":{"type":"string","description":"The root's text, cut to 300 characters (a call card is never cut)"},"media":{"description":"ID of an older single file on it, or null"},"medias":{"type":"array","items":{"type":"string"},"description":"IDs of its files"},"isDeleted":{"type":"boolean","description":"Whether the root was deleted (the thread lives on)"},"threadTitle":{"type":"string","description":"The thread's name, or null"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"}},"description":"Who sent the root (_id and name), or null"}},"description":"A small copy of the root to name the thread by. It also has pollData.question for a poll and threadStart: true for a thread started on purpose"},"replyCount":{"type":"integer","description":"How many replies it has"},"lastReplyAt":{"type":"string","format":"date-time","description":"When the latest reply came, or null"}}},"description":"Threads that match, newest activity first; empty when q is under 2 characters"}},"description":"The threads found"}}},"example":{"success":true,"data":{"threads":[{"rootId":"6ad1d0b2c3d4e5f6a7b8c901","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","isGroup":true,"root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","type":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","media":null,"medias":["6ad1d0d4e5f6a7b8c9dae101"],"isDeleted":false,"threadTitle":"October invoice","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"}},"replyCount":3,"lastReplyAt":"2026-10-16T06:40:12.000Z"}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/threads/{userId}/chat/{chatId}/unread":{"get":{"tags":["Threads"],"summary":"Count a chat's unread threads","description":"Lists the threads in one chat you are a member of that you follow, have not closed and have unread replies in, each with its count, looking at your newest 200 followed threads there.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getChatThreadsUnread","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"unreadThreadCount":{"type":"integer","description":"How many of the chat's threads you follow, have not closed and have unread replies in"},"threads":{"type":"array","items":{"type":"object","properties":{"rootId":{"type":"string","description":"ID of the thread's root"},"unreadCount":{"type":"integer","description":"Replies in it you have not read"}}},"description":"Those threads, newest reply first; empty in a chat without threads"}}},"example":{"success":true,"unreadThreadCount":1,"threads":[{"rootId":"6ad1d0b2c3d4e5f6a7b8c901","unreadCount":1}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/threads/{userId}/chat/{chatId}":{"get":{"tags":["Threads"],"summary":"List a chat's threads","description":"Lists the threads of one chat you are a member of, newest reply first: each thread's root, its 2 newest replies, your unread count (followed threads only) and whether you follow or closed it.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getChatThreads","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"before","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Only threads whose latest reply came before this time: the last thread's lastReplyAt, for the next page","example":"2026-10-15T14:02:00.000Z"},{"name":"filter","in":"query","required":false,"schema":{"type":"string","enum":["following","all","archived"]},"description":"all: every thread you have not closed (the default); following: threads you follow and have not closed; archived: threads you closed","example":"all"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50},"description":"Threads per page. Defaults to 20, at most 50","example":20}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"data":{"type":"object","properties":{"threads":{"type":"array","items":{"type":"object","properties":{"root":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"File ID; pass it as media_id when sending"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it was uploaded to"},"sender":{"type":"string","description":"ID of the person who uploaded it"},"messageId":{"type":"string","description":"ID of the message it is attached to"},"url":{"type":"string","description":"Signed link to download it, valid for up to 7 days"},"type":{"type":"string","description":"image, video or file"},"bucketName":{"type":"string","description":"Which store holds it"},"fileName":{"type":"string","description":"Its name as uploaded"},"minioPath":{"type":"string","description":"Key of the stored file"},"thumbHash":{"type":"string","description":"Tiny blurred placeholder to show while it loads; absent on older files"},"width":{"type":"integer","description":"Width in pixels (photos and videos); absent on older files"},"height":{"type":"integer","description":"Height in pixels (photos and videos); absent on older files"},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"minioPath":{"type":"string"},"bucketName":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"}},"description":"Small preview (640 px on the long edge) with its own signed url, minioPath, bucketName, width and height; absent until one is made"},"createdAt":{"type":"string","format":"date-time","description":"When it was uploaded"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"}}},"description":"Files attached to it"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions (everyone in the chat for @all)"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"Who reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"},"_id":{"type":"string","description":"ID of the reaction"}}},"description":"Emoji reactions to it"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"},"threadReplyCount":{"type":"integer","description":"How many replies it has, not counting deleted ones"},"threadLastReplyAt":{"type":"string","format":"date-time","description":"When the latest reply came (for a started thread with none, when it was started)"},"threadParticipants":{"type":"array","items":{"type":"string"},"description":"IDs of the people who replied, the most recent last"},"threadTitle":{"type":"string","description":"The thread's name; null when it has none (apps then show the root's first line)"},"threadTitleBy":{"type":"string","description":"ID of who named it; absent when it has no name"},"threadTitleAt":{"type":"string","format":"date-time","description":"When it was named; absent when it has no name"}},"description":"The thread's root message. Keys only some messages carry appear only when set: replyTo (the quoted message, filled in with its sender and files), replyToMediaId, replyToChat and replyToChatName, threadRoot and alsoInChannel (a thread reply), threadReplyCount, threadLastReplyAt, threadParticipants, threadTitle, threadTitleBy, threadTitleAt and threadStart (a thread's root), location, linkPreview, card (a bot's Kazee Card with its public state, plus your own answer as card.mine), forwardedFrom, storyRef, systemData, editedAt, deletedAt and findMeCode"},"chat":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the chat"},"chatName":{"type":"string","description":"The chat's name (a direct chat may have none)"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"},"participants":{"type":"array","items":{"type":"string"},"description":"IDs of the chat's members"}},"description":"The chat it is in; null if it could not be matched"},"latestReplies":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","description":"Files attached to it; empty here"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","description":"IDs of the people it mentions; empty here"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","description":"Emoji reactions to it; empty here"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"},"threadRoot":{"type":"string","description":"ID of the thread's root"}}},"description":"Its newest replies (up to 2), oldest first"},"unreadCount":{"type":"integer","description":"Replies you have not read; always 0 for a thread you do not follow"},"lastReplyAt":{"type":"string","format":"date-time","description":"When the latest reply came; pass the last thread's value as before for the next page"},"following":{"type":"boolean","description":"Whether you follow it"},"archived":{"type":"boolean","description":"Whether you closed it"}}},"description":"The threads, newest reply first; empty in a chat without threads"},"hasMore":{"type":"boolean","description":"Whether more threads follow; pass the last thread's lastReplyAt as before"}},"description":"A page of the chat's threads"}}},"example":{"success":true,"data":{"threads":[{"root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","status":"delivered","type":"image","interactive":{"buttons":[]},"medias":[{"_id":"6ad1d0d4e5f6a7b8c9dae101","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":"66f1b2c3d4e5f60718293a4b","messageId":"6ad1d0b2c3d4e5f6a7b8c901","url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"image","bucketName":"org-66a4b275003d1b495212b5aa","fileName":"delivery-note-october.jpg","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg","thumbHash":"1QcSHQRnh493V4dIh4eXh1h4kJUI","width":1600,"height":1200,"thumbnail":{"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg","bucketName":"org-66a4b275003d1b495212b5aa","width":640,"height":480},"createdAt":"2026-10-16T05:12:01.000Z","updatedAt":"2026-10-16T05:12:03.000Z","__v":0}],"viewedBy":["66f1b2c3d4e5f60718293a5c"],"mentions":["66f1b2c3d4e5f60718293a5c"],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","emoji":"👍","createdAt":"2026-10-16T05:14:40.000Z","_id":"6ad1d0f7b8c9daebfc0d1e01"}],"timestamp":"2026-10-16T05:12:03.000Z","createdAt":"2026-10-16T05:12:03.000Z","updatedAt":"2026-10-16T05:14:40.000Z","__v":0,"threadReplyCount":3,"threadLastReplyAt":"2026-10-16T06:40:12.000Z","threadParticipants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"threadTitle":"October invoice","threadTitleBy":"66f1b2c3d4e5f60718293a4b","threadTitleAt":"2026-10-16T05:20:00.000Z"},"chat":{"_id":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","isGroupChat":true,"participants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"]},"latestReplies":[{"_id":"6ad1d0b2c3d4e5f6a7b8c902","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"Filed it with the October invoice, thanks.","status":"delivered","type":"text","interactive":{"buttons":[]},"medias":[],"viewedBy":["66f1b2c3d4e5f60718293a4b"],"mentions":[],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[],"timestamp":"2026-10-16T06:40:12.000Z","createdAt":"2026-10-16T06:40:12.000Z","updatedAt":"2026-10-16T06:41:00.000Z","__v":0,"threadRoot":"6ad1d0b2c3d4e5f6a7b8c901"}],"unreadCount":1,"lastReplyAt":"2026-10-16T06:40:12.000Z","following":true,"archived":false}],"hasMore":false}}}}},"400":{"description":"filter is not following, all or archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/threads/{userId}":{"get":{"tags":["Threads"],"summary":"List my threads","description":"Lists your Threads view across all your chats, newest reply first: each thread's root, its 2 newest replies, its chat, your unread count (followed threads only) and whether you follow or closed it.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getThreads","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"before","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Only threads whose latest reply came before this time: the last thread's lastReplyAt, for the next page","example":"2026-10-15T14:02:00.000Z"},{"name":"filter","in":"query","required":false,"schema":{"type":"string","enum":["following","all","archived"]},"description":"following: threads you follow and have not closed (the default); all: every thread you have not closed; archived: threads you closed","example":"following"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":50},"description":"Threads per page. Defaults to 20, at most 50","example":20}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"data":{"type":"object","properties":{"threads":{"type":"array","items":{"type":"object","properties":{"root":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"File ID; pass it as media_id when sending"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it was uploaded to"},"sender":{"type":"string","description":"ID of the person who uploaded it"},"messageId":{"type":"string","description":"ID of the message it is attached to"},"url":{"type":"string","description":"Signed link to download it, valid for up to 7 days"},"type":{"type":"string","description":"image, video or file"},"bucketName":{"type":"string","description":"Which store holds it"},"fileName":{"type":"string","description":"Its name as uploaded"},"minioPath":{"type":"string","description":"Key of the stored file"},"thumbHash":{"type":"string","description":"Tiny blurred placeholder to show while it loads; absent on older files"},"width":{"type":"integer","description":"Width in pixels (photos and videos); absent on older files"},"height":{"type":"integer","description":"Height in pixels (photos and videos); absent on older files"},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"minioPath":{"type":"string"},"bucketName":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"}},"description":"Small preview (640 px on the long edge) with its own signed url, minioPath, bucketName, width and height; absent until one is made"},"createdAt":{"type":"string","format":"date-time","description":"When it was uploaded"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"}}},"description":"Files attached to it"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions (everyone in the chat for @all)"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"Who reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"},"_id":{"type":"string","description":"ID of the reaction"}}},"description":"Emoji reactions to it"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"},"threadReplyCount":{"type":"integer","description":"How many replies it has, not counting deleted ones"},"threadLastReplyAt":{"type":"string","format":"date-time","description":"When the latest reply came (for a started thread with none, when it was started)"},"threadParticipants":{"type":"array","items":{"type":"string"},"description":"IDs of the people who replied, the most recent last"},"threadTitle":{"type":"string","description":"The thread's name; null when it has none (apps then show the root's first line)"},"threadTitleBy":{"type":"string","description":"ID of who named it; absent when it has no name"},"threadTitleAt":{"type":"string","format":"date-time","description":"When it was named; absent when it has no name"}},"description":"The thread's root message. Keys only some messages carry appear only when set: replyTo (the quoted message, filled in with its sender and files), replyToMediaId, replyToChat and replyToChatName, threadRoot and alsoInChannel (a thread reply), threadReplyCount, threadLastReplyAt, threadParticipants, threadTitle, threadTitleBy, threadTitleAt and threadStart (a thread's root), location, linkPreview, card (a bot's Kazee Card with its public state, plus your own answer as card.mine), forwardedFrom, storyRef, systemData, editedAt, deletedAt and findMeCode"},"chat":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the chat"},"chatName":{"type":"string","description":"The chat's name (a direct chat may have none)"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"},"participants":{"type":"array","items":{"type":"string"},"description":"IDs of the chat's members"}},"description":"The chat it is in; null if it could not be matched"},"latestReplies":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","description":"Files attached to it; empty here"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","description":"IDs of the people it mentions; empty here"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","description":"Emoji reactions to it; empty here"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"},"threadRoot":{"type":"string","description":"ID of the thread's root"}}},"description":"Its newest replies (up to 2), oldest first"},"unreadCount":{"type":"integer","description":"Replies you have not read; always 0 for a thread you do not follow"},"lastReplyAt":{"type":"string","format":"date-time","description":"When the latest reply came; pass the last thread's value as before for the next page"},"following":{"type":"boolean","description":"Whether you follow it"},"archived":{"type":"boolean","description":"Whether you closed it"}}},"description":"The threads, newest reply first"},"hasMore":{"type":"boolean","description":"Whether more threads follow; pass the last thread's lastReplyAt as before"},"unreadThreadCount":{"type":"integer","description":"How many followed threads you have not closed have unread replies (the Threads badge); first page only"}},"description":"A page of your threads"}}},"example":{"success":true,"data":{"threads":[{"root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","status":"delivered","type":"image","interactive":{"buttons":[]},"medias":[{"_id":"6ad1d0d4e5f6a7b8c9dae101","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":"66f1b2c3d4e5f60718293a4b","messageId":"6ad1d0b2c3d4e5f6a7b8c901","url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"image","bucketName":"org-66a4b275003d1b495212b5aa","fileName":"delivery-note-october.jpg","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg","thumbHash":"1QcSHQRnh493V4dIh4eXh1h4kJUI","width":1600,"height":1200,"thumbnail":{"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg","bucketName":"org-66a4b275003d1b495212b5aa","width":640,"height":480},"createdAt":"2026-10-16T05:12:01.000Z","updatedAt":"2026-10-16T05:12:03.000Z","__v":0}],"viewedBy":["66f1b2c3d4e5f60718293a5c"],"mentions":["66f1b2c3d4e5f60718293a5c"],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","emoji":"👍","createdAt":"2026-10-16T05:14:40.000Z","_id":"6ad1d0f7b8c9daebfc0d1e01"}],"timestamp":"2026-10-16T05:12:03.000Z","createdAt":"2026-10-16T05:12:03.000Z","updatedAt":"2026-10-16T05:14:40.000Z","__v":0,"threadReplyCount":3,"threadLastReplyAt":"2026-10-16T06:40:12.000Z","threadParticipants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"threadTitle":"October invoice","threadTitleBy":"66f1b2c3d4e5f60718293a4b","threadTitleAt":"2026-10-16T05:20:00.000Z"},"chat":{"_id":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","isGroupChat":true,"participants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"]},"latestReplies":[{"_id":"6ad1d0b2c3d4e5f6a7b8c902","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"Filed it with the October invoice, thanks.","status":"delivered","type":"text","interactive":{"buttons":[]},"medias":[],"viewedBy":["66f1b2c3d4e5f60718293a4b"],"mentions":[],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[],"timestamp":"2026-10-16T06:40:12.000Z","createdAt":"2026-10-16T06:40:12.000Z","updatedAt":"2026-10-16T06:41:00.000Z","__v":0,"threadRoot":"6ad1d0b2c3d4e5f6a7b8c901"}],"unreadCount":1,"lastReplyAt":"2026-10-16T06:40:12.000Z","following":true,"archived":false}],"hasMore":false,"unreadThreadCount":1}}}}},"400":{"description":"filter is not following, all or archived","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/thread/{chatId}/{rootId}/{userId}":{"get":{"tags":["Threads"],"summary":"Read a thread","description":"Reads a thread in a chat you are a member of: its root and a page of its replies, oldest first, with whether you follow or closed it and how many replies you have not read. rootId may be the root or any reply in the thread. Reading does not mark replies read (Mark a thread as read does).\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getThread","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"rootId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the thread's root, or of any reply in it","example":"6ad1d0b2c3d4e5f6a7b8c901"},{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"},{"name":"before","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Only replies sent before this time: the first reply's createdAt, for the previous page. Ignored when not a date","example":"2026-10-16T06:40:12.000Z"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","maximum":200},"description":"Replies per page. Defaults to 50, at most 200","example":50}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"data":{"type":"object","properties":{"chatId":{"type":"string","description":"ID of the chat it is in"},"root":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"File ID; pass it as media_id when sending"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it was uploaded to"},"sender":{"type":"string","description":"ID of the person who uploaded it"},"messageId":{"type":"string","description":"ID of the message it is attached to"},"url":{"type":"string","description":"Signed link to download it, valid for up to 7 days"},"type":{"type":"string","description":"image, video or file"},"bucketName":{"type":"string","description":"Which store holds it"},"fileName":{"type":"string","description":"Its name as uploaded"},"minioPath":{"type":"string","description":"Key of the stored file"},"thumbHash":{"type":"string","description":"Tiny blurred placeholder to show while it loads; absent on older files"},"width":{"type":"integer","description":"Width in pixels (photos and videos); absent on older files"},"height":{"type":"integer","description":"Height in pixels (photos and videos); absent on older files"},"thumbnail":{"type":"object","properties":{"url":{"type":"string"},"minioPath":{"type":"string"},"bucketName":{"type":"string"},"width":{"type":"integer"},"height":{"type":"integer"}},"description":"Small preview (640 px on the long edge) with its own signed url, minioPath, bucketName, width and height; absent until one is made"},"createdAt":{"type":"string","format":"date-time","description":"When it was uploaded"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"}}},"description":"Files attached to it"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions (everyone in the chat for @all)"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"Who reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"},"_id":{"type":"string","description":"ID of the reaction"}}},"description":"Emoji reactions to it"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"},"threadReplyCount":{"type":"integer","description":"How many replies it has, not counting deleted ones"},"threadLastReplyAt":{"type":"string","format":"date-time","description":"When the latest reply came (for a started thread with none, when it was started)"},"threadParticipants":{"type":"array","items":{"type":"string"},"description":"IDs of the people who replied, the most recent last"},"threadTitle":{"type":"string","description":"The thread's name; null when it has none (apps then show the root's first line)"},"threadTitleBy":{"type":"string","description":"ID of who named it; absent when it has no name"},"threadTitleAt":{"type":"string","format":"date-time","description":"When it was named; absent when it has no name"}},"description":"The thread's root message. Keys only some messages carry appear only when set: replyTo (the quoted message, filled in with its sender and files), replyToMediaId, replyToChat and replyToChatName, threadRoot and alsoInChannel (a thread reply), threadReplyCount, threadLastReplyAt, threadParticipants, threadTitle, threadTitleBy, threadTitleAt and threadStart (a thread's root), location, linkPreview, card (a bot's Kazee Card with its public state, plus your own answer as card.mine), forwardedFrom, storyRef, systemData, editedAt, deletedAt and findMeCode"},"replies":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","description":"Files attached to it; empty here"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","description":"IDs of the people it mentions; empty here"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","description":"Emoji reactions to it; empty here"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"},"threadRoot":{"type":"string","description":"ID of the thread's root"}}},"description":"The newest page of replies, oldest first; deleted ones stay in place with type deleted"},"hasMoreBefore":{"type":"boolean","description":"Whether older replies exist; pass the first reply's createdAt as before to get them"},"isFollowing":{"type":"boolean","description":"Whether you follow the thread"},"isArchived":{"type":"boolean","description":"Whether you closed it"},"unreadCount":{"type":"integer","description":"Replies you have not read"}},"description":"The thread"}}},"example":{"success":true,"data":{"chatId":"6ad1d0a1c2b3a4f5e6d7c801","root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","status":"delivered","type":"image","interactive":{"buttons":[]},"medias":[{"_id":"6ad1d0d4e5f6a7b8c9dae101","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":"66f1b2c3d4e5f60718293a4b","messageId":"6ad1d0b2c3d4e5f6a7b8c901","url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"image","bucketName":"org-66a4b275003d1b495212b5aa","fileName":"delivery-note-october.jpg","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/delivery-note-october-2026-10-16_08-12-03.jpg","thumbHash":"1QcSHQRnh493V4dIh4eXh1h4kJUI","width":1600,"height":1200,"thumbnail":{"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/thumbs/delivery-note-october-2026-10-16_08-12-03.jpg","bucketName":"org-66a4b275003d1b495212b5aa","width":640,"height":480},"createdAt":"2026-10-16T05:12:01.000Z","updatedAt":"2026-10-16T05:12:03.000Z","__v":0}],"viewedBy":["66f1b2c3d4e5f60718293a5c"],"mentions":["66f1b2c3d4e5f60718293a5c"],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","emoji":"👍","createdAt":"2026-10-16T05:14:40.000Z","_id":"6ad1d0f7b8c9daebfc0d1e01"}],"timestamp":"2026-10-16T05:12:03.000Z","createdAt":"2026-10-16T05:12:03.000Z","updatedAt":"2026-10-16T05:14:40.000Z","__v":0,"threadReplyCount":3,"threadLastReplyAt":"2026-10-16T06:40:12.000Z","threadParticipants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"threadTitle":"October invoice","threadTitleBy":"66f1b2c3d4e5f60718293a4b","threadTitleAt":"2026-10-16T05:20:00.000Z"},"replies":[{"_id":"6ad1d0b2c3d4e5f6a7b8c902","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"Filed it with the October invoice, thanks.","status":"delivered","type":"text","interactive":{"buttons":[]},"medias":[],"viewedBy":["66f1b2c3d4e5f60718293a4b"],"mentions":[],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[],"timestamp":"2026-10-16T06:40:12.000Z","createdAt":"2026-10-16T06:40:12.000Z","updatedAt":"2026-10-16T06:41:00.000Z","__v":0,"threadRoot":"6ad1d0b2c3d4e5f6a7b8c901"}],"hasMoreBefore":false,"isFollowing":true,"isArchived":false,"unreadCount":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of, or no thread with that ID in it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/callLogs/{userId}":{"get":{"tags":["Calls"],"summary":"List my call history","description":"Lists the calls you made or received that ended, were missed or were rejected, newest first. Each entry is one person ringing another, so inviting someone into a running call is an entry too. Calls still ringing or in progress, and calls that failed to connect, are left out.\n\n**Permission:** `chat.calls.read` (View call logs).","operationId":"getCallLogs","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); any other ID is refused","example":"66f1b2c3d4e5f60718293a4b"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","default":50},"description":"How many calls to return","example":20},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","default":0},"description":"How many of the newest calls to skip, for paging","example":20}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"callLogs":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the call record"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chat":{"type":"object","properties":{"_id":{"type":"string"},"isGroupChat":{"type":"boolean"}},"description":"The chat the call was made from: its _id and isGroupChat only (its name is not included)"},"caller":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the person"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"Address of their photo, valid for a limited time; absent when they have none, null when it cannot be read"}},"description":"The person who rang"},"callee":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the person"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"Address of their photo, valid for a limited time; absent when they have none, null when it cannot be read"}},"description":"The person who was rung"},"callType":{"type":"string","description":"audio or video"},"status":{"type":"string","description":"ended (it was answered and finished), missed or rejected"},"roomId":{"type":"integer","description":"Number of the call's room on the call server"},"callAttemptId":{"type":"string","description":"ID of this call attempt"},"startedAt":{"type":"string","format":"date-time","description":"When it started ringing"},"answeredAt":{"type":"string","format":"date-time","description":"When it was answered; absent if it never was"},"endedAt":{"type":"string","format":"date-time","description":"When it ended"},"duration":{"type":"integer","description":"Seconds from answer to end; 0 when it was not answered"},"message":{"type":"string","description":"ID of the call's entry in the chat"},"historyPending":{"type":"boolean","description":"Internal: whether the call's chat entry is still to be written"},"createdAt":{"type":"string","format":"date-time","description":"When the record was made"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"},"direction":{"type":"string","description":"outgoing when you rang, incoming when you were rung"}}},"description":"Your finished calls, newest first"}}},"example":{"callLogs":[{"_id":"6ad1d2d4e5f6a7b8c9d0e101","organizationId":"66a4b275003d1b495212b5aa","chat":{"_id":"6ad1d0a1c2b3a4f5e6d7c802","isGroupChat":false},"caller":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a"},"callee":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a"},"callType":"video","status":"ended","roomId":48213377,"callAttemptId":"ca-7f3a9e15b2d44c8e9f1a2d6b","startedAt":"2026-10-16T07:30:02.000Z","answeredAt":"2026-10-16T07:30:09.000Z","endedAt":"2026-10-16T07:42:43.000Z","duration":754,"message":"6ad1d0b2c3d4e5f6a7b8c902","historyPending":false,"createdAt":"2026-10-16T07:30:02.000Z","updatedAt":"2026-10-16T07:42:44.000Z","__v":0,"direction":"outgoing"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not your own ID, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"userId is not a valid ID, or the history could not be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.calls.read"]}],"x-required-scopes":["chat.calls.read"]}},"/searchMessages":{"get":{"tags":["Search"],"summary":"Search messages","description":"Searches the text and captions of messages in your chats by whole words, best match first, and optionally the names of files sent in them. Without chatId it searches every chat you are a member of, leaving out chats you archived unless includeArchived is true. A hit in a thread says which thread, so it can be opened there.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"searchMessages","parameters":[{"name":"chatId","in":"query","required":false,"schema":{"type":"string"},"description":"Search this chat only (one you are a member of, archived or not)","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"includeArchived","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"true to also search chats you archived (without chatId)","example":false},{"name":"includeMedia","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"true to also search the names of files sent in the chats. In the query string any non-empty value turns it on, even \"false\": leave it out to skip files","example":true},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":50,"default":20},"description":"Hits per page, 1 to 50 (message hits and file hits each)","example":20},{"name":"page","in":"query","required":false,"schema":{"type":"integer","default":1},"description":"Page number, from 1","example":1},{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"Words to look for, at least 2 characters. Whole words match, in any case (\"invoice\" finds invoices too)","example":"invoice"},{"name":"userId","in":"query","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"results":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the message"},"chatId":{"type":"string","description":"ID of its chat"},"chatName":{"type":"string","description":"The chat's name; a one-on-one is named by the other person"},"type":{"type":"string","description":"message"},"messageType":{"type":"string","description":"For a hit on a photo, video or file caption: image, video or file; absent for text"},"content":{"type":"string","description":"Its full text or caption"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"}},"description":"Who sent it (_id and name)"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"highlight":{"type":"string","description":"Up to about 100 characters around the first match, matches wrapped in <mark>"},"thread":{"type":"object","properties":{"rootId":{"type":"string","description":"ID of the thread's root"},"root":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the root"},"type":{"type":"string","description":"The root's message type"},"content":{"type":"string","description":"The root's text, cut to 300 characters (a call card is never cut)"},"media":{"description":"ID of an older single file on it, or null"},"medias":{"type":"array","items":{"type":"string"},"description":"IDs of its files"},"isDeleted":{"type":"boolean","description":"Whether the root was deleted (the thread lives on)"},"threadTitle":{"type":"string","description":"The thread's name, or null"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"}},"description":"Who sent the root (_id and name), or null"}},"description":"A small copy of the root to name the thread by, or null if it is gone. It also has pollData.question for a poll and threadStart: true for a thread started on purpose"},"replyCount":{"type":"integer","description":"How many replies the thread has"}},"description":"The thread the hit is the root of or a reply in, to name and open it; absent otherwise"}}},"description":"What matched. On the first page, threads whose name matches come first (up to 3), then message hits, best match first; then, with includeMedia, file hits: { _id, chatId, chatName, type: \"media\", fileName, mediaType, mediaUrl (a signed download link), sender (always empty), timestamp, highlight }. A hit on a photo, video or file caption also has messageType (image, video or file); a reply in a thread also has threadRoot, the ID of the thread's root"},"pagination":{"type":"object","properties":{"page":{"type":"integer","description":"The page asked for"},"totalPages":{"type":"integer","description":"How many pages the message and file hits fill"},"totalResults":{"type":"integer","description":"How many hits in all, counting the named threads on the first page"},"hasMore":{"type":"boolean","description":"Whether a later page exists"}},"description":"Where this page sits"},"query":{"type":"string","description":"The words searched for, trimmed"}}},"example":{"success":true,"results":[{"_id":"6ad1d0b2c3d4e5f6a7b8c901","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","type":"message","messageType":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"},"timestamp":"2026-10-16T05:12:03.000Z","highlight":"Signed delivery note for the October <mark>invoice</mark>. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it toda...","thread":{"rootId":"6ad1d0b2c3d4e5f6a7b8c901","root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","type":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","media":null,"medias":["6ad1d0d4e5f6a7b8c9dae101"],"isDeleted":false,"threadTitle":"October invoice","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"}},"replyCount":3}},{"_id":"6ad1d0b2c3d4e5f6a7b8c902","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","type":"message","content":"Filed it with the October invoice, thanks.","sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno"},"timestamp":"2026-10-16T06:40:12.000Z","highlight":"Filed it with the October <mark>invoice</mark>, thanks.","threadRoot":"6ad1d0b2c3d4e5f6a7b8c901","thread":{"rootId":"6ad1d0b2c3d4e5f6a7b8c901","root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","type":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","media":null,"medias":["6ad1d0d4e5f6a7b8c9dae101"],"isDeleted":false,"threadTitle":"October invoice","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"}},"replyCount":3}}],"pagination":{"page":1,"totalPages":1,"totalResults":2,"hasMore":false},"query":"invoice"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"query is under 2 characters, limit is outside 1 to 50, chatId is not a valid ID, or the search index is still being built","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/universalSearch":{"get":{"tags":["Search"],"summary":"Search everything","description":"Searches your chats, the people in your organisation and the messages in your chats at once, for a search box. Chats you archived are left out unless includeArchived is true.\n\n**Permission:** `chat.search.read` (Search chat).","operationId":"universalSearch","parameters":[{"name":"includeArchived","in":"query","required":false,"schema":{"type":"boolean","default":false},"description":"true to also search chats you archived and their messages","example":false},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":20,"default":5},"description":"How many results per section, 1 to 20","example":5},{"name":"query","in":"query","required":true,"schema":{"type":"string"},"description":"What to look for, at least 2 characters. Chats and people match any part of a name (or email); messages match whole words","example":"invoice"},{"name":"userId","in":"query","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"query":{"type":"string","description":"The words searched for, trimmed"},"sections":{"type":"object","properties":{"chats":{"type":"array","items":{"type":"object","properties":{"chatId":{"type":"string","description":"ID of the chat"},"name":{"type":"string","description":"The group's name, or the other person's name for a one-on-one"},"isGroup":{"type":"boolean","description":"Whether it is a group"},"participants":{"type":"array","items":{"type":"string"},"description":"Names of the other members"}}},"description":"Your chats that match: a group by its name, a one-on-one by the other person's name (never by yours or another member's), best match first. A one-on-one also has userId, the other person's user ID"},"contacts":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"email":{"type":"string","description":"Their email address"}}},"description":"People in your organisation whose name or email matches, best match first: not you, not disabled, not an app login, not someone else's personal bot, and not someone already listed under chats as a one-on-one"},"messages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the message"},"chatId":{"type":"string","description":"ID of its chat"},"chatName":{"type":"string","description":"The chat's name; a one-on-one is named by the other person"},"type":{"type":"string","description":"message"},"messageType":{"type":"string","description":"For a hit on a photo, video or file caption: image, video or file; absent for text"},"content":{"type":"string","description":"Its full text or caption"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"}},"description":"Who sent it (_id and name)"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"highlight":{"type":"string","description":"Up to about 100 characters around the first match, matches wrapped in <mark>"},"thread":{"type":"object","properties":{"rootId":{"type":"string","description":"ID of the thread's root"},"root":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the root"},"type":{"type":"string","description":"The root's message type"},"content":{"type":"string","description":"The root's text, cut to 300 characters (a call card is never cut)"},"media":{"description":"ID of an older single file on it, or null"},"medias":{"type":"array","items":{"type":"string"},"description":"IDs of its files"},"isDeleted":{"type":"boolean","description":"Whether the root was deleted (the thread lives on)"},"threadTitle":{"type":"string","description":"The thread's name, or null"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"}},"description":"Who sent the root (_id and name), or null"}},"description":"A small copy of the root to name the thread by, or null if it is gone. It also has pollData.question for a poll and threadStart: true for a thread started on purpose"},"replyCount":{"type":"integer","description":"How many replies the thread has"}},"description":"The thread the hit is the root of or a reply in, to name and open it; absent otherwise"}}},"description":"Messages in your chats whose text or caption matches by whole words, best match first, led by threads whose name matches. A hit on a photo, video or file caption also has messageType (image, video or file); a reply in a thread also has threadRoot, the ID of the thread's root"},"threads":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the message"},"chatId":{"type":"string","description":"ID of its chat"},"chatName":{"type":"string","description":"The chat's name; a one-on-one is named by the other person"},"type":{"type":"string","description":"message"},"messageType":{"type":"string","description":"For a hit on a photo, video or file caption: image, video or file; absent for text"},"content":{"type":"string","description":"Its full text or caption"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"}},"description":"Who sent it (_id and name)"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"highlight":{"type":"string","description":"Up to about 100 characters around the first match, matches wrapped in <mark>"},"thread":{"type":"object","properties":{"rootId":{"type":"string","description":"ID of the thread's root"},"root":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the root"},"type":{"type":"string","description":"The root's message type"},"content":{"type":"string","description":"The root's text, cut to 300 characters (a call card is never cut)"},"media":{"description":"ID of an older single file on it, or null"},"medias":{"type":"array","items":{"type":"string"},"description":"IDs of its files"},"isDeleted":{"type":"boolean","description":"Whether the root was deleted (the thread lives on)"},"threadTitle":{"type":"string","description":"The thread's name, or null"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"}},"description":"Who sent the root (_id and name), or null"}},"description":"A small copy of the root to name the thread by, or null if it is gone. It also has pollData.question for a poll and threadStart: true for a thread started on purpose"},"replyCount":{"type":"integer","description":"How many replies the thread has"}},"description":"The thread the hit is the root of or a reply in, to name and open it; absent otherwise"}}},"description":"Just the threads whose name matches (up to 3, at most limit), in the same form as messages, for apps that list them apart"}},"description":"The results, by kind, each cut to limit"}}},"example":{"success":true,"query":"invoice","sections":{"chats":[{"chatId":"6ad1d0a1c2b3a4f5e6d7c802","name":"Invoice approvals","isGroup":true,"participants":["Brian Otieno","Wanjiku Mwangi"]}],"contacts":[{"id":"66f1b2c3d4e5f60718293a6d","name":"Invoicing Desk","email":"invoices@inet.africa"}],"messages":[{"_id":"6ad1d0b2c3d4e5f6a7b8c901","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","type":"message","messageType":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"},"timestamp":"2026-10-16T05:12:03.000Z","highlight":"Signed delivery note for the October <mark>invoice</mark>. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it toda...","thread":{"rootId":"6ad1d0b2c3d4e5f6a7b8c901","root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","type":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","media":null,"medias":["6ad1d0d4e5f6a7b8c9dae101"],"isDeleted":false,"threadTitle":"October invoice","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"}},"replyCount":3}},{"_id":"6ad1d0b2c3d4e5f6a7b8c902","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","type":"message","content":"Filed it with the October invoice, thanks.","sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno"},"timestamp":"2026-10-16T06:40:12.000Z","highlight":"Filed it with the October <mark>invoice</mark>, thanks.","threadRoot":"6ad1d0b2c3d4e5f6a7b8c901","thread":{"rootId":"6ad1d0b2c3d4e5f6a7b8c901","root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","type":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","media":null,"medias":["6ad1d0d4e5f6a7b8c9dae101"],"isDeleted":false,"threadTitle":"October invoice","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"}},"replyCount":3}}],"threads":[{"_id":"6ad1d0b2c3d4e5f6a7b8c901","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chatName":"Finance team","type":"message","messageType":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"},"timestamp":"2026-10-16T05:12:03.000Z","highlight":"Signed delivery note for the October <mark>invoice</mark>. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it toda...","thread":{"rootId":"6ad1d0b2c3d4e5f6a7b8c901","root":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","type":"image","content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","media":null,"medias":["6ad1d0d4e5f6a7b8c9dae101"],"isDeleted":false,"threadTitle":"October invoice","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru"}},"replyCount":3}}]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"query is under 2 characters, limit is outside 1 to 20, or the search index is still being built","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.search.read"]}],"x-required-scopes":["chat.search.read"]}},"/stories/contacts/{userId}":{"get":{"tags":["Stories"],"summary":"List stories","description":"Lists the live stories for your story tray: your own, and those of everyone who shares a chat with you, except people whose stories you muted. Each story says whether you have seen it, its reactions and how many comments it has. Browsers may reuse the answer for 60 seconds; new stories arrive over the live connection.\n\n**Permission:** `chat.stories.read` (View stories).","operationId":"getStories","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Ignored: the stories are always the ones you can see. The path still needs a value; send your own user ID","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"myStories":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Story ID"},"userId":{"type":"string","description":"ID of the person who posted it"},"mediaUrl":{"type":"string","description":"Link to the picture or video, valid 7 days without sign-in"},"mediaType":{"type":"string","description":"image or video"},"posterUrl":{"type":"string","description":"For a video, link to a still of its first frame; null otherwise"},"caption":{"type":"string","description":"The caption; absent if none"},"createdAt":{"type":"string","format":"date-time","description":"When it was posted"},"expiresAt":{"type":"string","format":"date-time","description":"When it disappears: 24 hours after posting"},"viewerCount":{"type":"integer","description":"How many people have seen it"},"isViewed":{"type":"boolean","description":"Whether you have seen it; always true for your own"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of the person who reacted"},"userName":{"type":"string","description":"Their name when they reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted (your own stories only)"}}},"description":"Reactions on it, oldest first; a person may leave several different emoji"},"commentCount":{"type":"integer","description":"How many comments and replies it has, not counting deleted ones"}}},"description":"Your own live stories, oldest first"},"contactStories":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of the person"},"userName":{"type":"string","description":"Their name"},"userPhoto":{"type":"string","description":"Link to their small profile photo; null if none"},"statuses":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Story ID"},"userId":{"type":"string","description":"ID of the person who posted it"},"mediaUrl":{"type":"string","description":"Link to the picture or video, valid 7 days without sign-in"},"mediaType":{"type":"string","description":"image or video"},"posterUrl":{"description":"For a video, link to a still of its first frame; null otherwise"},"caption":{"type":"string","description":"The caption; absent if none"},"createdAt":{"type":"string","format":"date-time","description":"When it was posted"},"expiresAt":{"type":"string","format":"date-time","description":"When it disappears: 24 hours after posting"},"viewerCount":{"type":"integer","description":"How many people have seen it"},"isViewed":{"type":"boolean","description":"Whether you have seen it; always true for your own"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of the person who reacted"},"userName":{"type":"string","description":"Their name when they reacted"},"emoji":{"type":"string","description":"The emoji"}}},"description":"Reactions on it, oldest first; a person may leave several different emoji"},"commentCount":{"type":"integer","description":"How many comments and replies it has, not counting deleted ones"}}},"description":"Their live stories, oldest first"},"hasUnviewed":{"type":"boolean","description":"Whether any of their stories is one you have not seen"}}},"description":"Live stories of people who share a chat with you, one entry per person, people with stories you have not seen first, then the most recent"}}},"example":{"success":true,"myStories":[{"_id":"6ad1d0e5f6a7b8c9daebf201","userId":"66f1b2c3d4e5f60718293a4b","mediaUrl":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/stories/66f1b2c3d4e5f60718293a4b/team-lunch-2026-10-16_06-30-44.mp4?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","mediaType":"video","posterUrl":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/stories/66f1b2c3d4e5f60718293a4b/team-lunch-2026-10-16_06-30-44-poster.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","caption":"Team lunch","createdAt":"2026-10-16T06:30:44.000Z","expiresAt":"2026-10-17T06:30:44.000Z","viewerCount":4,"isViewed":true,"reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","userName":"Brian Otieno","emoji":"🔥","createdAt":"2026-10-16T06:20:00.000Z"}],"commentCount":2}],"contactStories":[{"userId":"66f1b2c3d4e5f60718293a5c","userName":"Brian Otieno","userPhoto":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a5c/brian-2026-09-11_14-02-31-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","statuses":[{"_id":"6ad1d0e5f6a7b8c9daebf202","userId":"66f1b2c3d4e5f60718293a5c","mediaUrl":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/stories/66f1b2c3d4e5f60718293a5c/sunrise-2026-10-16_06-05-12.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","mediaType":"image","posterUrl":null,"caption":"Sunrise over Ngong Hills","createdAt":"2026-10-16T06:05:12.000Z","expiresAt":"2026-10-17T06:05:12.000Z","viewerCount":7,"isViewed":false,"reactions":[{"userId":"66f1b2c3d4e5f60718293a4b","userName":"Amina Wanjiru","emoji":"😍"}],"commentCount":1}],"hasUnviewed":true}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"The stories could not be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.read"]}],"x-required-scopes":["chat.stories.read"]}},"/stories/{storyId}/viewers":{"get":{"tags":["Stories"],"summary":"List who saw my story","description":"Lists who has seen one of your stories, latest first, a page at a time, with each viewer's reaction if they left one. Only the person who posted the story can see this.\n\n**Permission:** `chat.stories.read` (View stories).","operationId":"getStoryViewers","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf201"},{"name":"before","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Only viewers who saw it before this time: the nextCursor of the page before","example":"2026-10-16T06:41:09.000Z"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200},"description":"How many viewers per page. Defaults to 50; more than 200 is cut to 200","example":50},{"name":"userId","in":"query","required":false,"schema":{"type":"string"},"description":"Ignored: you must be the story's owner. Older apps still send it","example":"66f1b2c3d4e5f60718293a4b","deprecated":true}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"viewers":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of the person"},"userName":{"type":"string","description":"Their name; Unknown if they are no longer in Chat"},"userPhoto":{"type":"string","description":"Link to their profile photo; null if none"},"viewedAt":{"type":"string","format":"date-time","description":"When they first saw it"},"reaction":{"type":"object","properties":{"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"}},"description":"Their reaction to it, or null; if they left several, the last one"}}},"description":"People who saw it, latest first, each with their reaction"},"hasMore":{"type":"boolean","description":"Whether there are more, older viewers"},"nextCursor":{"type":"string","format":"date-time","description":"Pass as before to get the next page; null when there are no more"}}},"example":{"success":true,"viewers":[{"userId":"66f1b2c3d4e5f60718293a5c","userName":"Brian Otieno","userPhoto":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a5c/brian-2026-09-11_14-02-31.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","viewedAt":"2026-10-16T06:41:09.000Z","reaction":{"emoji":"🔥","createdAt":"2026-10-16T06:41:30.000Z"}},{"userId":"66f1b2c3d4e5f60718293a6d","userName":"Grace Mwangi","userPhoto":null,"viewedAt":"2026-10-16T06:33:51.000Z","reaction":null}],"hasMore":true,"nextCursor":"2026-10-16T06:33:51.000Z"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The story is not yours","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No story with that ID, or it has disappeared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.read"]}],"x-required-scopes":["chat.stories.read"]}},"/stories/mutes":{"get":{"tags":["Stories"],"summary":"List people whose stories I muted","description":"Lists the people whose stories you have muted, so they stay out of your story tray.\n\n**Permission:** `chat.stories.read` (View stories).","operationId":"getStoryMutes","responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"mutedUserIds":{"type":"array","items":{"type":"string"},"description":"IDs of the people whose stories you have muted; empty when none"}}},"example":{"success":true,"mutedUserIds":["66f1b2c3d4e5f60718293a5c"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"500":{"description":"Your mutes could not be read","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.read"]}],"x-required-scopes":["chat.stories.read"]},"post":{"tags":["Stories"],"summary":"Mute or unmute someone's stories","description":"Hides one person's stories from your story tray, or shows them again. Muting someone already muted, or unmuting someone who is not, changes nothing. It does not look the person up.\n\n**Permission:** `chat.stories.update` (React to stories).","operationId":"setStoryMute","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"op":{"type":"string","enum":["mute","unmute"],"description":"mute to hide their stories, unmute to show them again","examples":["mute"]},"targetUserId":{"type":"string","description":"ID of the person whose stories to mute or unmute","examples":["66f1b2c3d4e5f60718293a5c"]}},"required":["op","targetUserId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"op":{"type":"string","description":"What was done: mute or unmute"},"targetUserId":{"type":"string","description":"The person"}}},"example":{"success":true,"op":"mute","targetUserId":"66f1b2c3d4e5f60718293a5c"}}}},"400":{"description":"op is not mute or unmute, or targetUserId is you","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"targetUserId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.update"]}],"x-required-scopes":["chat.stories.update"]}},"/stories/{storyId}/comments":{"get":{"tags":["Stories"],"summary":"List a story's comments","description":"Lists the comments on a story, newest first, a page at a time. Each comes with its reply count and its latest 2 replies; get the rest with listStoryCommentReplies. Deleted comments are left out. Open to the story's owner and anyone who shares a chat with them.\n\n**Permission:** `chat.comments.read` (Read story comments).","operationId":"listStoryComments","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf202"},{"name":"before","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Only comments written before this time: the nextCursor of the page before. An unreadable date is ignored","example":"2026-10-16T06:22:10.000Z"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100},"description":"How many comments per page. Defaults to 30; more than 100 is cut to 100","example":30}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"comments":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Comment ID"},"storyId":{"type":"string","description":"ID of the story"},"storyOwnerId":{"type":"string","description":"ID of the person who posted the story"},"userId":{"type":"string","description":"ID of the person who wrote the comment"},"userName":{"type":"string","description":"Their name when they wrote it"},"userPhoto":{"type":"string","description":"Link to their profile photo as it was when they wrote it; null if none"},"content":{"type":"string","description":"The text, with mentions written as @[Name](userId)"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people mentioned in it"},"parentCommentId":{"description":"For a reply, the comment it answers; null for a comment on the story itself"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of the person who reacted"},"userName":{"type":"string","description":"Their name when they reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"}}},"description":"Reactions on it, at most one per person"},"replyCount":{"type":"integer","description":"How many replies it has; always 0 for a reply"},"createdAt":{"type":"string","format":"date-time","description":"When it was written"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"isMine":{"type":"boolean","description":"Whether you wrote it"},"replyPreview":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"storyId":{"type":"string"},"storyOwnerId":{"type":"string"},"userId":{"type":"string"},"userName":{"type":"string"},"userPhoto":{"type":"string"},"content":{"type":"string"},"mentions":{"type":"array"},"parentCommentId":{"type":"string"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string"},"userName":{"type":"string"},"emoji":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}},"replyCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"isMine":{"type":"boolean"},"replyPreview":{"type":"array"}}},"description":"Its latest 2 replies, oldest first, shaped like a comment (each with an empty replyPreview)"}}},"description":"Comments on the story itself, newest first, each with its latest replies"},"hasMore":{"type":"boolean","description":"Whether there are more, older comments"},"nextCursor":{"description":"Pass as before to get the next page; null when there are no more"}}},"example":{"success":true,"comments":[{"_id":"6ad1d1a7b8c9daebfc0d1e01","storyId":"6ad1d0e5f6a7b8c9daebf202","storyOwnerId":"66f1b2c3d4e5f60718293a5c","userId":"66f1b2c3d4e5f60718293a4b","userName":"Amina Wanjiru","userPhoto":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","content":"Beautiful! @[Grace Mwangi](66f1b2c3d4e5f60718293a6d) we should hike there","mentions":["66f1b2c3d4e5f60718293a6d"],"parentCommentId":null,"reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","userName":"Brian Otieno","emoji":"👍","createdAt":"2026-10-16T06:20:00.000Z"}],"replyCount":1,"createdAt":"2026-10-16T06:22:10.000Z","updatedAt":"2026-10-16T06:22:10.000Z","isMine":true,"replyPreview":[{"_id":"6ad1d1a7b8c9daebfc0d1e02","storyId":"6ad1d0e5f6a7b8c9daebf202","storyOwnerId":"66f1b2c3d4e5f60718293a5c","userId":"66f1b2c3d4e5f60718293a5c","userName":"Brian Otieno","userPhoto":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a5c/brian-2026-09-11_14-02-31.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","content":"Saturday?","mentions":[],"parentCommentId":"6ad1d1a7b8c9daebfc0d1e01","reactions":[{"userId":"66f1b2c3d4e5f60718293a4b","userName":"Amina Wanjiru","emoji":"😂","createdAt":"2026-10-16T06:26:30.000Z"}],"replyCount":0,"createdAt":"2026-10-16T06:25:00.000Z","updatedAt":"2026-10-16T06:25:00.000Z","isMine":false,"replyPreview":[]}]}],"hasMore":false,"nextCursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You do not share a chat with the story's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No story with that ID, or it has disappeared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.comments.read"]}],"x-required-scopes":["chat.comments.read"]},"post":{"tags":["Stories"],"summary":"Comment on a story","description":"Adds a comment that everyone who can see the story can read, or a reply to a comment (one level only). Open to the story's owner and anyone who shares a chat with them. Everyone who can see the story sees it appear live. The story's owner, people @mentioned and, for a reply, the comment's author and others in that thread are told in their notifications chat.\n\n**Permission:** `chat.comments.create` (Add story comments).","operationId":"addStoryComment","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf202"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","maxLength":1000,"description":"The comment, up to 1000 characters after trimming spaces. Mention someone with @[Name](userId)","examples":["Beautiful! @[Grace Mwangi](66f1b2c3d4e5f60718293a6d) we should hike there"]},"parentCommentId":{"type":"string","description":"To reply, the ID of a comment on the story itself (not a reply). Leave out for a comment on the story","examples":["6ad1d1a7b8c9daebfc0d1e01"]}},"required":["content"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"comment":{"type":"object","properties":{"_id":{"type":"string","description":"Comment ID"},"storyId":{"type":"string","description":"ID of the story"},"storyOwnerId":{"type":"string","description":"ID of the person who posted the story"},"userId":{"type":"string","description":"ID of the person who wrote the comment"},"userName":{"type":"string","description":"Their name when they wrote it"},"userPhoto":{"type":"string","description":"Link to their profile photo as it was when they wrote it; null if none"},"content":{"type":"string","description":"The text, with mentions written as @[Name](userId)"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people mentioned in it"},"parentCommentId":{"description":"For a reply, the comment it answers; null for a comment on the story itself"},"reactions":{"type":"array","description":"Reactions on it, at most one per person"},"replyCount":{"type":"integer","description":"How many replies it has; always 0 for a reply"},"createdAt":{"type":"string","format":"date-time","description":"When it was written"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"}},"description":"The new comment"}}},"example":{"success":true,"comment":{"_id":"6ad1d1a7b8c9daebfc0d1e01","storyId":"6ad1d0e5f6a7b8c9daebf202","storyOwnerId":"66f1b2c3d4e5f60718293a5c","userId":"66f1b2c3d4e5f60718293a4b","userName":"Amina Wanjiru","userPhoto":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","content":"Beautiful! @[Grace Mwangi](66f1b2c3d4e5f60718293a6d) we should hike there","mentions":["66f1b2c3d4e5f60718293a6d"],"parentCommentId":null,"reactions":[],"replyCount":0,"createdAt":"2026-10-16T06:22:10.000Z","updatedAt":"2026-10-16T06:22:10.000Z"}}}}},"400":{"description":"content is empty or over 1000 characters, or parentCommentId is itself a reply","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You do not share a chat with the story's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No story with that ID (or it has disappeared), or no comment parentCommentId on this story","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"The story has expired, or the comment you are replying to was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId or parentCommentId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.comments.create"]}],"x-required-scopes":["chat.comments.create"]}},"/stories/{storyId}/comments/{commentId}/replies":{"get":{"tags":["Stories"],"summary":"List replies to a story comment","description":"Lists the replies to one comment on a story, oldest first, a page at a time. Open to the story's owner and anyone who shares a chat with them.\n\n**Permission:** `chat.comments.read` (Read story comments).","operationId":"listStoryCommentReplies","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf202"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the comment whose replies you want","example":"6ad1d1a7b8c9daebfc0d1e01"},{"name":"after","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Only replies written after this time: the nextCursor of the page before. An unreadable date is ignored","example":"2026-10-16T06:25:00.000Z"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100},"description":"How many replies per page. Defaults to 30; more than 100 is cut to 100","example":30}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"replies":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Comment ID"},"storyId":{"type":"string","description":"ID of the story"},"storyOwnerId":{"type":"string","description":"ID of the person who posted the story"},"userId":{"type":"string","description":"ID of the person who wrote the comment"},"userName":{"type":"string","description":"Their name when they wrote it"},"userPhoto":{"type":"string","description":"Link to their profile photo as it was when they wrote it; null if none"},"content":{"type":"string","description":"The text, with mentions written as @[Name](userId)"},"mentions":{"type":"array","description":"IDs of the people mentioned in it"},"parentCommentId":{"type":"string","description":"For a reply, the comment it answers; null for a comment on the story itself"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of the person who reacted"},"userName":{"type":"string","description":"Their name when they reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"}}},"description":"Reactions on it, at most one per person"},"replyCount":{"type":"integer","description":"How many replies it has; always 0 for a reply"},"createdAt":{"type":"string","format":"date-time","description":"When it was written"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"isMine":{"type":"boolean","description":"Whether you wrote it"}}},"description":"Replies to the comment, oldest first; deleted ones are left out"},"hasMore":{"type":"boolean","description":"Whether there are more, newer replies"},"nextCursor":{"description":"Pass as after to get the next page; null when there are no more"}}},"example":{"success":true,"replies":[{"_id":"6ad1d1a7b8c9daebfc0d1e02","storyId":"6ad1d0e5f6a7b8c9daebf202","storyOwnerId":"66f1b2c3d4e5f60718293a5c","userId":"66f1b2c3d4e5f60718293a5c","userName":"Brian Otieno","userPhoto":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a5c/brian-2026-09-11_14-02-31.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","content":"Saturday?","mentions":[],"parentCommentId":"6ad1d1a7b8c9daebfc0d1e01","reactions":[{"userId":"66f1b2c3d4e5f60718293a4b","userName":"Amina Wanjiru","emoji":"😂","createdAt":"2026-10-16T06:26:30.000Z"}],"replyCount":0,"createdAt":"2026-10-16T06:25:00.000Z","updatedAt":"2026-10-16T06:25:00.000Z","isMine":false}],"hasMore":false,"nextCursor":null}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You do not share a chat with the story's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No story with that ID (or it has disappeared), or no such comment on it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId or commentId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.comments.read"]}],"x-required-scopes":["chat.comments.read"]}},"/notifications/by-source":{"get":{"tags":["Notifications"],"summary":"List my notifications","description":"Lists your own notifications, newest first, a page at a time, optionally only those from one app or item, read or unread, or of one type. Apps use it to show only their own notifications.\n\n**Permission:** `chat.notifications.read` (Read notifications).","operationId":"notifications_by_source","parameters":[{"name":"isRead","in":"query","required":false,"schema":{"type":"boolean"},"description":"true for read notifications only; false (or any other value) for unread only; leave out for both","example":false},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":50},"description":"How many per page; 0 or text that is not a number means 50. There is no upper limit","example":20},{"name":"notificationType","in":"query","required":false,"schema":{"type":"string","enum":["mention","reply","reaction","comment_added","system","marketing","pin"]},"description":"Only notifications of this type","example":"mention"},{"name":"skip","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0},"description":"How many to skip, for the next page","example":0},{"name":"source","in":"query","required":false,"schema":{"type":"string"},"description":"Only notifications from this source. With a colon it must match exactly (spaces:task); without, it matches every source that starts with it and a colon (spaces matches spaces:task and spaces:event)","example":"spaces:task"},{"name":"sourceEntityId","in":"query","required":false,"schema":{"type":"string"},"description":"Only notifications about this item, e.g. a task ID","example":"6ad1d1e1f2a3b4c5d6e7f801"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"notifications":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Notification ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"user":{"type":"string","description":"ID of the person it is for"},"category":{"type":"string","description":"Free-text kind the sender gave, e.g. task, story, reaction"},"notificationType":{"type":"string","description":"mention, reply, reaction, comment_added, system, marketing or pin"},"source":{"type":"string","description":"Which app and kind of item it came from, e.g. spaces:task; absent for older notifications"},"sourceEntityId":{"type":"string","description":"ID of that item, for opening it"},"actorId":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"email":{"type":"string","description":"Their email address"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"}},"description":"Where their photo is stored (not a link)"}},"description":"The person who caused it: _id, name, email and stored profile photo"},"content":{"type":"string","description":"The notification text"},"title":{"type":"string","description":"The notification heading"},"data":{"type":"object","properties":{"entityType":{"type":"string"},"entityTitle":{"type":"string"}},"description":"Extra details the sending app attached, for opening the right screen"},"success":{"type":"boolean","description":"Whether the push worked, or true when there was no phone to push to"},"isRead":{"type":"boolean","description":"Whether it has been marked read"},"createdAt":{"type":"string","format":"date-time","description":"When it was made"},"__v":{"type":"integer","description":"Internal version counter"}}},"description":"Your notifications that match, newest first. A notification may also carry chatId and messageId (the chat and message it came from) and, once read, readAt (when it was marked read)"},"pagination":{"type":"object","properties":{"total":{"type":"integer","description":"How many notifications match in all"},"limit":{"type":"integer","description":"The page size used"},"skip":{"type":"integer","description":"How many were skipped"},"hasMore":{"type":"boolean","description":"Whether there are more after this page"}},"description":"Where this page sits"}}},"example":{"notifications":[{"_id":"6ad1d1b8c9daebfc0d1e2f01","organizationId":"66a4b275003d1b495212b5aa","user":"66f1b2c3d4e5f60718293a4b","category":"task","notificationType":"mention","source":"spaces:task","sourceEntityId":"6ad1d1e1f2a3b4c5d6e7f801","actorId":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian.otieno@example.com","profilePhoto":{"minioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a5c/brian-2026-09-11_14-02-31.jpg","bucketName":"org-66a4b275003d1b495212b5aa"}},"content":"@Amina Wanjiru can you send this today?","title":"Brian Otieno mentioned you on Send the October invoice","data":{"entityType":"task","entityTitle":"Send the October invoice"},"success":true,"isRead":false,"createdAt":"2026-10-16T06:40:00.000Z","__v":0}],"pagination":{"total":1,"limit":20,"skip":0,"hasMore":false}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.notifications.read"]}],"x-required-scopes":["chat.notifications.read"]}},"/notifications/unread-count":{"get":{"tags":["Notifications"],"summary":"Count my unread notifications","description":"Counts your unread notifications, optionally only those from one app or item kind.\n\n**Permission:** `chat.notifications.read` (Read notifications).","operationId":"notifications_unread_count","parameters":[{"name":"source","in":"query","required":false,"schema":{"type":"string"},"description":"Only notifications from this source. With a colon it must match exactly (spaces:task); without, it matches every source that starts with it and a colon (spaces matches spaces:task and spaces:event)","example":"spaces"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","description":"How many of your notifications are unread"}}},"example":{"count":3}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.notifications.read"]}],"x-required-scopes":["chat.notifications.read"]}},"/notifications/{userId}":{"get":{"tags":["Notifications"],"summary":"List a person's notifications","description":"Lists all of one person's notifications in your organisation, newest first, for administrators.\n\n**Permission:** `chat.notifications.admin` (Bulk-mark notifications).","operationId":"notifications_action_user_all","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the person","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"notifications":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Notification ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"user":{"type":"string","description":"ID of the person it is for"},"category":{"type":"string","description":"Free-text kind the sender gave, e.g. task, story, reaction"},"notificationType":{"type":"string","description":"mention, reply, reaction, comment_added, system, marketing or pin"},"source":{"type":"string","description":"Which app and kind of item it came from, e.g. spaces:task; absent for older notifications"},"sourceEntityId":{"type":"string","description":"ID of that item, for opening it"},"actorId":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"email":{"type":"string","description":"Their email address"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"}},"description":"Where their photo is stored (not a link)"}},"description":"The person who caused it: _id, name, email and stored profile photo"},"content":{"type":"string","description":"The notification text"},"title":{"type":"string","description":"The notification heading"},"data":{"type":"object","properties":{"entityType":{"type":"string"},"entityTitle":{"type":"string"}},"description":"Extra details the sending app attached, for opening the right screen"},"success":{"type":"boolean","description":"Whether the push worked, or true when there was no phone to push to"},"isRead":{"type":"boolean","description":"Whether it has been marked read"},"createdAt":{"type":"string","format":"date-time","description":"When it was made"},"__v":{"type":"integer","description":"Internal version counter"}}},"description":"Every notification the person has had, newest first, with no paging; ones whose push failed are left out. A notification may also carry chatId and messageId (the chat and message it came from) and, once read, readAt (when it was marked read)"}}},"example":{"notifications":[{"_id":"6ad1d1b8c9daebfc0d1e2f01","organizationId":"66a4b275003d1b495212b5aa","user":"66f1b2c3d4e5f60718293a4b","category":"task","notificationType":"mention","source":"spaces:task","sourceEntityId":"6ad1d1e1f2a3b4c5d6e7f801","actorId":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian.otieno@example.com","profilePhoto":{"minioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a5c/brian-2026-09-11_14-02-31.jpg","bucketName":"org-66a4b275003d1b495212b5aa"}},"content":"@Amina Wanjiru can you send this today?","title":"Brian Otieno mentioned you on Send the October invoice","data":{"entityType":"task","entityTitle":"Send the October invoice"},"success":true,"isRead":false,"createdAt":"2026-10-16T06:40:00.000Z","__v":0}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"userId is not a valid ID; the answer is { error, status }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.notifications.admin"]}],"x-required-scopes":["chat.notifications.admin"]}},"/user/{userId}/fcm_token":{"put":{"tags":["Settings"],"summary":"Register a phone for notifications","description":"Registers this device's push notification token for you, so it gets Chat's notifications for 30 days; register again on each app start to keep it. It removes your other tokens of the same kind, so one device of each kind is kept: with platform and device_os, those with the same two; with platform alone, every token with that platform; with neither, every token you have, phones included.\n\n**Permission:** `chat.users.update` (Update own profile).","operationId":"setFCMtoken","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"device_os":{"type":"string","description":"The phone's system with platform rn: ios or android","examples":["android"]},"fcm_token":{"type":"string","description":"The device's Firebase push token","examples":["eXb3kQ9zR0m:APA91bH4x2Lr7Yd0Vt8sWq1nJc5uKp3oZa6fGi9eTb2hMw4yNd7lQx"]},"meeting_rings":{"type":"boolean","description":"true to have this phone ring for meetings you are invited to; only an Android phone (platform rn, device_os android) can ring. Must be a JSON true","examples":[true]},"platform":{"type":"string","description":"Which app: rn from the Kazee Chat phone app, web from the web app. Older apps leave it out","examples":["rn"]}},"required":["fcm_token"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"user":{"type":"object","properties":{"_id":{"type":"string","description":"User ID"},"name":{"type":"string","description":"Full name"},"email":{"type":"string","description":"Email address"},"phone":{"type":"string","description":"Phone number"},"organizationId":{"type":"string","description":"ID of your organisation"},"role":{"type":"string","description":"Your role in the organisation, as Kazee sign-in names it"},"type":{"type":"string","description":"Human for a person, AI for a bot"},"onboarded":{"type":"boolean","description":"Whether you have finished Chat's first-run welcome"},"pbxExtension":{"type":"string","description":"Your office phone extension, if you have one"},"zohoId":{"type":"string","description":"Your ID in Zoho, if you are linked to it"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string","description":"Where the full photo is stored"},"bucketName":{"type":"string","description":"Which store holds it"},"thumbMinioPath":{"type":"string","description":"Where the 256-pixel version is stored; absent on older photos"},"thumbBucketName":{"type":"string","description":"Which store holds the 256-pixel version"}},"description":"Where your profile photo is stored (not a link; getUser gives the link)"},"commands":{"type":"array","description":"Slash commands a bot offers; always empty for a person"},"createdAt":{"type":"string","format":"date-time","description":"When Chat first saw you"},"updatedAt":{"type":"string","format":"date-time","description":"When your record last changed"},"__v":{"type":"integer","description":"Internal version counter"}},"description":"Your record (the token itself is never sent back)"}}},"example":{"success":true,"user":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina.wanjiru@example.com","phone":"+254712345678","organizationId":"66a4b275003d1b495212b5aa","role":"Member","type":"Human","onboarded":true,"pbxExtension":"214","zohoId":"4876000000123001","profilePhoto":{"minioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"commands":[],"createdAt":"2026-03-04T07:30:00.000Z","updatedAt":"2026-10-16T06:15:00.000Z","__v":0}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"fcm_token is empty or not text, or your record is not in Chat; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.update"]}],"x-required-scopes":["chat.users.update"]}},"/user/{userId}/voip_token":{"put":{"tags":["Settings"],"summary":"Register an iPhone for incoming calls","description":"Registers an iPhone's call push token for you, so incoming Chat calls ring it like a phone call for 30 days; register again on each app start to keep it. Earlier tokens are kept until their own 30 days run out. Meetings do not ring through it.\n\n**Permission:** `chat.users.update` (Update own profile).","operationId":"setVoIPtoken","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"voip_token":{"type":"string","description":"The iPhone's call push token, as hex text","examples":["5f2d8c41a9e07b36c1d4e8f2a7b05c9e3d61f48a2c7e9b0d5a3f61c8e2b49d70"]}},"required":["voip_token"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"Always \"VoIP token registered\""}}},"example":{"success":true,"message":"VoIP token registered"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.update"]}],"x-required-scopes":["chat.users.update"]}},"/chat/{chatId}":{"put":{"tags":["Chats"],"summary":"Update a group","description":"Changes a group's name, description, photo or how bots answer in it. Only an admin who is still a member may. Send only what changes; an empty chatName is ignored. Members see the change live, and a change to how bots answer also posts a notice in the group (without a push). Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"updateChat","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the group","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assistantAction":{"type":"string","enum":["assistant_tagged_reply","assistant_passive","assistant_free_reply"],"description":"How bots answer in the group: assistant_tagged_reply (only when tagged or replied to), assistant_passive (read everything, reply when they can help) or assistant_free_reply (reply to everything)","examples":["assistant_passive"]},"chatName":{"type":"string","description":"New name","examples":["Finance team"]},"description":{"type":"string","description":"New description; an empty text clears it","examples":["Invoices, payments, month-end and audits"]},"profilePhoto":{"type":"object","description":"A photo already stored, as { minioPath, bucketName } (what setChatProfilePhoto returns), or a photo address as text. To upload a new photo, use setChatProfilePhoto","examples":[{"minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa"}]},"requesterId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["requesterId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"chat":{"type":"object","properties":{"_id":{"type":"string","description":"Chat ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"participants":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"profilePhoto":{"type":"string"},"type":{"type":"string"}}},"description":"The members (_id, name, email, profilePhoto address, type)"},"lastMessage":{"type":"string","description":"ID of the newest message"},"chatName":{"type":"string","description":"The group's name, or the name given to a direct chat"},"profilePhoto":{"type":"string","description":"Address of the group's photo; absent when there is none"},"description":{"type":"string","description":"What the group is for"},"isGroupChat":{"type":"boolean","description":"true for a group or channel, false for a direct chat"},"groupAdmins":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"}}},"description":"The group's admins (_id, name, email)"},"assistantAction":{"type":"string","description":"How bots answer here: assistant_tagged_reply (only when tagged or replied to), assistant_passive (read everything, reply when they can help) or assistant_free_reply (reply to everything)"},"chatType":{"type":"string","description":"chat, comment (a comment chat of a task or other item), external or notifications"},"seq":{"type":"integer","description":"Number of the chat's latest change; pass it as this chat's cursor to syncChanges"},"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"messageId":{"type":"string"},"pinnedBy":{"type":"string"},"pinnedAt":{"type":"string","format":"date-time"},"notifyMode":{"type":"string"}}},"description":"Pinned messages (messageId, pinnedBy, pinnedAt, notifyMode)"},"createdAt":{"type":"string","format":"date-time","description":"When the chat was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last had activity or changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"The group after the change"}}},"example":{"success":true,"chat":{"_id":"6ad1d0a1c2b3a4f5e6d7c801","organizationId":"66a4b275003d1b495212b5aa","participants":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina@inet.africa","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","type":"Human"}],"lastMessage":"6ad1d0b2c3d4e5f6a7b8c901","chatName":"Finance team","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","description":"Invoices, payments, month-end and audits","isGroupChat":true,"groupAdmins":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina@inet.africa"}],"assistantAction":"assistant_tagged_reply","chatType":"chat","seq":42,"pinnedMessages":[{"_id":"6ad1d1c9d0e1f2a3b4c5d601","messageId":"6ad1d0b2c3d4e5f6a7b8c902","pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedAt":"2026-10-14T06:30:00.000Z","notifyMode":"notify"}],"createdAt":"2026-09-01T07:00:00.000Z","updatedAt":"2026-10-16T09:30:00.000Z","__v":3}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"requesterId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: assistantAction is not one of the three, no chat with that ID, it is a space or meeting room (change it in Spaces), another app manages it, it is not a group, you are not an admin who is still a member, nothing to change was sent, or chatId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/chatGroup/{groupId}":{"put":{"tags":["Chat folders"],"summary":"Update a chat folder","description":"Renames one of your folders or changes its colour, icon or position. Send only what changes. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.groups.update` (Update chat folders).","operationId":"updateChatGroup","parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the folder","example":"6ad1d1a7b8c9d0e1f2a3b401"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"color":{"type":"string","description":"New colour as a hex code","examples":["#22c55e"]},"icon":{"type":"string","description":"New icon name","examples":["star"]},"name":{"type":"string","maxLength":50,"description":"New name, up to 50 characters","examples":["Clients"]},"order":{"type":"integer","description":"New position among your folders; lower comes first","examples":[1]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"group":{"type":"object","properties":{"_id":{"type":"string","description":"Folder ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"userId":{"type":"string","description":"ID of the person who owns the folder"},"name":{"type":"string","description":"Its name, up to 50 characters, unique among your folders"},"color":{"type":"string","description":"Its colour as a hex code"},"icon":{"type":"string","description":"Its icon name, if any, e.g. briefcase"},"order":{"type":"integer","description":"Its position among your folders; lower comes first"},"pinnedChats":{"type":"array","items":{"type":"string"},"description":"IDs of the chats pinned at the top of this folder"},"createdAt":{"type":"string","format":"date-time","description":"When it was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"The folder after the change"}}},"example":{"success":true,"group":{"_id":"6ad1d1a7b8c9d0e1f2a3b401","organizationId":"66a4b275003d1b495212b5aa","userId":"66f1b2c3d4e5f60718293a4b","name":"Clients","color":"#22c55e","icon":"star","order":1,"pinnedChats":["6ad1d0a1c2b3a4f5e6d7c801"],"createdAt":"2026-10-01T07:00:00.000Z","updatedAt":"2026-10-16T09:00:00.000Z","__v":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: no folder of yours with that ID, you already have a folder with that name, the name is over 50 characters, or groupId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.groups.update"]}],"x-required-scopes":["chat.groups.update"]},"delete":{"tags":["Chat folders"],"summary":"Delete a chat folder","description":"Deletes one of your folders. The chats in it are not touched; they just leave the folder. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.groups.delete` (Delete chat folders).","operationId":"deleteChatGroup","parameters":[{"name":"groupId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the folder","example":"6ad1d1a7b8c9d0e1f2a3b401"},{"name":"userId","in":"query","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"A confirmation sentence"}}},"example":{"success":true,"message":"Group deleted successfully"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: no folder of yours with that ID, or groupId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.groups.delete"]}],"x-required-scopes":["chat.groups.delete"]}},"/message/{id}/card":{"put":{"tags":["Messages"],"summary":"Change a card I sent","description":"Lets the sender of an interactive card (usually a bot) close or reopen it, put a short note on it, or replace it with a new card of the same kind. Answers given so far are kept. Readers in the chat (or thread) see the change live; replacing the card also rebuilds the plain text older apps show, unless you send content. Send any mix of status, note and card.\n\n**Permission:** `chat.messages.update` (Edit messages).","operationId":"updateCard","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the card's message","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"card":{"type":"object","description":"A whole new card of the same kind (as when sending one: v, kind, title, input, policy and so on; a JSON text also works). Its state and the answers so far are kept","examples":[{"v":1,"kind":"decision","title":"Approve the October fibre invoice?","body":"KES 184,000 from Liquid Telecom, due 20 Oct.","input":{"options":[{"id":"approve","label":"Approve","style":"primary"},{"id":"reject","label":"Reject","style":"danger"}]},"recommendation":{"option":"approve","label":"Approve"},"policy":{"responders":["66f1b2c3d4e5f60718293a4b"],"mode":"first","results":"live","anonymous":false,"closesAt":"2026-10-20T09:00:00.000Z"}}]},"content":{"type":"string","description":"With card: the plain text older apps show instead of the card. Defaults to text built from the card","examples":["Approve the October fibre invoice? Reply approve or reject."]},"note":{"type":"string","maxLength":200,"description":"A short line shown on the card, up to 200 characters; an empty text removes it","examples":["Paid by bank transfer instead."]},"status":{"type":"string","enum":["closed","open"],"description":"closed stops answers; open lets answers in again (not for a card that has been decided)","examples":["closed"]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"messageId":{"type":"string","description":"ID of the card's message"},"card":{"type":"object","properties":{"v":{"type":"integer","description":"Card format: 1, 2 when it uses newer building blocks, 3 with a link block, 4 with a view block (a bot's HTML page: page, preview, label and the server's previewUrl, the preview picture's address)"},"kind":{"type":"string","description":"decision, choice, rating, slider, report or form"},"title":{"type":"string","description":"The question or heading"},"body":{"type":"string","description":"Text under the title"},"input":{"type":"object","properties":{"options":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"style":{"type":"string"}}}}},"description":"What the reader can answer with (for a decision: 2 to 4 options with id, label and style)"},"recommendation":{"type":"object","properties":{"option":{"type":"string"},"label":{"type":"string"}},"description":"The option or value the sender suggests (option or value, and label)"},"policy":{"type":"object","properties":{"responders":{"type":"array","items":{"type":"string"}},"mode":{"type":"string"},"results":{"type":"string"},"anonymous":{"type":"boolean"},"closesAt":{"type":"string","format":"date-time"}},"description":"Who may answer (responders: anyone or a list of user IDs), mode (first, each or changeable), when results show (live, closed or hidden), whether answers are anonymous, and closesAt"},"state":{"type":"object","properties":{"status":{"type":"string"},"responses":{"type":"integer"},"closedReason":{"type":"string"},"closedAt":{"type":"string","format":"date-time"},"note":{"type":"string"}},"description":"Where it stands: status (open or closed), responses, closedReason (decided, deadline or bot), closedAt, counts per option when results show, decided, and the sender's note"}},"description":"The card as every reader now sees it (no one's individual answers)"}}},"example":{"success":true,"messageId":"6ad1d0b2c3d4e5f6a7b8c901","card":{"v":1,"kind":"decision","title":"Approve the October fibre invoice?","body":"KES 184,000 from Liquid Telecom, due 20 Oct.","input":{"options":[{"id":"approve","label":"Approve","style":"primary"},{"id":"reject","label":"Reject","style":"danger"}]},"recommendation":{"option":"approve","label":"Approve"},"policy":{"responders":["66f1b2c3d4e5f60718293a4b"],"mode":"first","results":"live","anonymous":false,"closesAt":"2026-10-20T09:00:00.000Z"},"state":{"status":"closed","responses":0,"closedReason":"bot","closedAt":"2026-10-16T09:40:00.000Z","note":"Paid by bank transfer instead."}}}}}},"400":{"description":"The message has no card, the new card is not valid or is a different kind, status is not closed or open, a decided card cannot reopen, or the note is too long","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"Only the card's sender can change it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No message with that ID, or it was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"id is not a valid ID, or the card could not be saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.update"]}],"x-required-scopes":["chat.messages.update"]}},"/message/{id}/view/push":{"put":{"tags":["Messages"],"summary":"Push data into my HTML view","description":"For the bot that sent a view card: sends data into every open copy of the page in the chat (socket view:data, which the page reads with kazee.on), or only into the copies one member has open when to is given. Nothing is stored: a copy opened later does not get it.\n\n**Permission:** `chat.messages.update` (Edit messages).","operationId":"pushHtmlView","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the view card's message","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","description":"Any JSON value whose JSON is at most 16384 bytes; the page's kazee.on handlers receive it as it is","examples":[{"selected":"master","ahead":3}]},"to":{"type":"string","description":"ID of one member of the chat: only their open copies get the data. Left out, everyone's do","examples":["66f1b2c3d4e5f60718293a4b"]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"success":true}}}},"400":{"description":"data-required: no data; too-large: the JSON of data is over 16384 bytes; or bad-recipient: to is not a user ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"sender-only: only the bot that sent the view card may push into it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"message-not-found: no message with that ID, or it was deleted; not-a-view: the message carries no view card; or recipient-not-found: to is not a member of the chat","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"unavailable: the push could not be sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.update"]}],"x-required-scopes":["chat.messages.update"]}},"/message/{id}":{"put":{"tags":["Messages"],"summary":"Edit a message","description":"Changes the text or caption of a message you sent; the previous text is kept in its edit history and it is marked edited. Everyone in the chat sees the change live. A bot showing its answer bit by bit sends streaming: true, which neither marks it edited nor keeps the history.\n\n**Permission:** `chat.messages.update` (Edit messages).","operationId":"updateMessage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the message","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","description":"The new text or caption, in full","examples":["The October invoices went out this morning, except Westlands Mall's."]},"streaming":{"type":"boolean","description":"true for a bot revealing its answer in steps: the message is not marked edited and no history is kept","examples":[false]}},"required":["content"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"messageId":{"type":"string","description":"ID of the message"},"content":{"type":"string","description":"Its text now"}}},"example":{"success":true,"messageId":"6ad1d0b2c3d4e5f6a7b8c901","content":"The October invoices went out this morning, except Westlands Mall's."}}}},"400":{"description":"The message cannot be edited: only text, photo, video, file and interactive messages can","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You did not send the message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No message with that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"id is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.update"]}],"x-required-scopes":["chat.messages.update"]},"delete":{"tags":["Messages"],"summary":"Delete a message","description":"Deletes a message you sent, for everyone. It keeps its place in the chat as type deleted with its text, files, card, reactions, mentions and edit history removed, and everyone in the chat sees it go live. A deleted thread reply stops counting in its thread, and a pinned message is unpinned.\n\n**Permission:** `chat.messages.delete` (Delete messages).","operationId":"deleteMessage","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the message","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"messageId":{"type":"string","description":"ID of the deleted message"}}},"example":{"success":true,"messageId":"6ad1d0b2c3d4e5f6a7b8c901"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You did not send the message","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No message with that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"id is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.delete"]}],"x-required-scopes":["chat.messages.delete"]}},"/users/profiles":{"post":{"tags":["People"],"summary":"Get profile photos for several people","description":"Gets small profile photo links for up to 500 people in your organisation in one call, for people pickers. Repeated IDs are counted once.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getUserProfiles","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userIds":{"type":"array","items":{"type":"string"},"description":"IDs of the people, at most 500, as a JSON list","examples":[["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"]]}},"required":["userIds"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"users":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"User ID"},"profilePicture":{"type":"string","description":"Link to their small (256-pixel) profile photo, or the full photo if no small one exists, valid 7 days; null if they have none"}}},"description":"One entry per person found, in no set order; IDs not found and people whose account is turned off are left out"}}},"example":{"success":true,"users":[{"_id":"66f1b2c3d4e5f60718293a4b","profilePicture":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d"},{"_id":"66f1b2c3d4e5f60718293a5c","profilePicture":null}]}}}},"400":{"description":"userIds is missing, not a list, has more than 500 IDs, or holds something that is not a user ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]}},"/sync":{"post":{"tags":["Chats"],"summary":"Catch up on chat changes","description":"Brings a device up to date in one call. Send the seq you last saw for each chat; the reply has the chats added, updated and removed for you, and for each changed chat the messages that changed (as they are now), the messages that went away and new read receipts. A chat whose changes are too old to replay (over 30 days, or a cursor the server never had) comes back with resync: true: reload it from scratch. Changes are capped at limitPerChat messages per chat (newest first, more: true when there were more) and about 1,500 messages per reply (partial: true).\n\n**Permission:** `chat.chats.read` (Read chats) and `chat.messages.read` (Read messages).","operationId":"syncChanges","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"chatType":{"type":"string","enum":["chat","comment","external","notifications"],"default":"chat","description":"Which chats to sync; chat also covers your notifications chat","examples":["chat"]},"cursors":{"type":"object","description":"For each chat you already hold, its ID and the seq you last saw. Leave out on a first call. Entries that are not a chat ID and a number of 0 or more are ignored; at most 2,000 are read","examples":[{"6ad1d0a1c2b3a4f5e6d7c801":40,"6ad1d0a1c2b3a4f5e6d7c802":17}]},"limitPerChat":{"type":"integer","minimum":1,"maximum":50,"description":"Most changed messages to send per chat. Defaults to 50, which is also the most","examples":[50]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"serverTime":{"type":"string","format":"date-time","description":"The server's time when it answered"},"partial":{"type":"boolean","description":"true when some changed chats were left for the next call (too many messages for one reply): call again straight away"},"chats":{"type":"object","properties":{"added":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Chat ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"participants":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"The person's user ID"},"name":{"type":"string","description":"Their name"},"email":{"type":"string","description":"Their email address"},"phone":{"type":"string","description":"Their phone number"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"},"profilePhoto":{"type":"string","description":"Address of their photo (the small copy when there is one), or null"},"online":{"type":"boolean","description":"Whether they are connected to Chat now"},"lastSeen":{"type":"string","format":"date-time","description":"When they were last connected, or null when unknown"},"inCall":{"type":"boolean","description":"Whether they are in a call now"},"inCallKind":{"description":"internal for a Kazee call, external for a phone call through the office phone system; null when not in a call"}}},"description":"The members, as chat-list rows"},"lastMessage":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"type":{"type":"string"},"profilePhoto":{"type":"string"}},"description":"Who sent it (_id, name, email, phone, type, profilePhoto)"},"content":{"type":"string","description":"Its text"},"type":{"type":"string","description":"text, image, video, file, audio, call, location, system, poll, story_reply, interactive, notification or deleted"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions"},"reactions":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"userId":{"type":"string"},"emoji":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"description":"Emoji reactions (userId, emoji, createdAt)"},"medias":{"type":"array","description":"Files attached to it"},"edited":{"type":"boolean","description":"Whether it was edited"},"isDeleted":{"type":"boolean","description":"Whether it was deleted"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was stored"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"The newest message in the chat itself (not in a thread); absent when there is none"},"chatName":{"type":"string","description":"The group's name; for a direct chat, the other person's name"},"profilePhoto":{"type":"string","description":"Address of the group's photo; for a direct chat, the other person's photo; null when there is none"},"description":{"type":"string","description":"What the group is for"},"isGroupChat":{"type":"boolean","description":"true for a group or channel, false for a direct chat"},"groupAdmins":{"type":"array","items":{"type":"string"},"description":"IDs of the group's admins"},"assistantAction":{"type":"string","description":"How bots answer here: assistant_tagged_reply (only when tagged or replied to), assistant_passive (read everything, reply when they can help) or assistant_free_reply (reply to everything)"},"chatType":{"type":"string","description":"chat, comment (a comment chat of a task or other item), external or notifications"},"seq":{"type":"integer","description":"Number of the chat's latest change; pass it as this chat's cursor to syncChanges"},"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"messageId":{"type":"string"},"pinnedBy":{"type":"string"},"pinnedAt":{"type":"string","format":"date-time"},"notifyMode":{"type":"string"}}},"description":"Pinned messages (messageId, pinnedBy, pinnedAt, notifyMode)"},"createdAt":{"type":"string","format":"date-time","description":"When the chat was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last had activity or changed"},"__v":{"type":"integer","description":"Internal revision counter"},"markedUnread":{"type":"boolean","description":"Whether you marked the chat as unread"},"isPinned":{"type":"boolean","description":"Whether you pinned it to the top of your list"},"pinnedAt":{"type":"string","format":"date-time","description":"When you pinned it, or null"},"isArchived":{"type":"boolean","description":"Whether you archived it"},"archiveVersion":{"type":"integer","description":"How many times you archived or restored it; pass it as expectedVersion to setChatArchived"},"threadActivityAt":{"type":"string","format":"date-time","description":"When a thread you follow here last had a reply, or null"},"unreadMessagesCount":{"type":"integer","description":"Messages from others you have not read"},"unreadMentionsCount":{"type":"integer","description":"How many of those mention you"}}},"description":"Chats you are in that you sent no cursor for (all of them on a first call), as chat-list rows"},"updated":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Chat ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"participants":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"The person's user ID"},"name":{"type":"string","description":"Their name"},"email":{"type":"string","description":"Their email address"},"phone":{"type":"string","description":"Their phone number"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"},"profilePhoto":{"type":"string","description":"Address of their photo (the small copy when there is one), or null"},"online":{"type":"boolean","description":"Whether they are connected to Chat now"},"lastSeen":{"type":"string","format":"date-time","description":"When they were last connected, or null when unknown"},"inCall":{"type":"boolean","description":"Whether they are in a call now"},"inCallKind":{"description":"internal for a Kazee call, external for a phone call through the office phone system; null when not in a call"}}},"description":"The members, as chat-list rows"},"lastMessage":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"type":{"type":"string"},"profilePhoto":{"type":"string"}},"description":"Who sent it (_id, name, email, phone, type, profilePhoto)"},"content":{"type":"string","description":"Its text"},"type":{"type":"string","description":"text, image, video, file, audio, call, location, system, poll, story_reply, interactive, notification or deleted"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions"},"reactions":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"userId":{"type":"string"},"emoji":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"description":"Emoji reactions (userId, emoji, createdAt)"},"medias":{"type":"array","description":"Files attached to it"},"edited":{"type":"boolean","description":"Whether it was edited"},"isDeleted":{"type":"boolean","description":"Whether it was deleted"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was stored"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"The newest message in the chat itself (not in a thread); absent when there is none"},"chatName":{"type":"string","description":"The group's name; for a direct chat, the other person's name"},"profilePhoto":{"type":"string","description":"Address of the group's photo; for a direct chat, the other person's photo; null when there is none"},"description":{"type":"string","description":"What the group is for"},"isGroupChat":{"type":"boolean","description":"true for a group or channel, false for a direct chat"},"groupAdmins":{"type":"array","items":{"type":"string"},"description":"IDs of the group's admins"},"assistantAction":{"type":"string","description":"How bots answer here: assistant_tagged_reply (only when tagged or replied to), assistant_passive (read everything, reply when they can help) or assistant_free_reply (reply to everything)"},"chatType":{"type":"string","description":"chat, comment (a comment chat of a task or other item), external or notifications"},"seq":{"type":"integer","description":"Number of the chat's latest change; pass it as this chat's cursor to syncChanges"},"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"messageId":{"type":"string"},"pinnedBy":{"type":"string"},"pinnedAt":{"type":"string","format":"date-time"},"notifyMode":{"type":"string"}}},"description":"Pinned messages (messageId, pinnedBy, pinnedAt, notifyMode)"},"createdAt":{"type":"string","format":"date-time","description":"When the chat was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last had activity or changed"},"__v":{"type":"integer","description":"Internal revision counter"},"markedUnread":{"type":"boolean","description":"Whether you marked the chat as unread"},"isPinned":{"type":"boolean","description":"Whether you pinned it to the top of your list"},"pinnedAt":{"type":"string","format":"date-time","description":"When you pinned it, or null"},"isArchived":{"type":"boolean","description":"Whether you archived it"},"archiveVersion":{"type":"integer","description":"How many times you archived or restored it; pass it as expectedVersion to setChatArchived"},"threadActivityAt":{"type":"string","format":"date-time","description":"When a thread you follow here last had a reply, or null"},"unreadMessagesCount":{"type":"integer","description":"Messages from others you have not read"},"unreadMentionsCount":{"type":"integer","description":"How many of those mention you"}}},"description":"Chats that changed after your cursor, as fresh chat-list rows"},"removed":{"type":"array","items":{"type":"string"},"description":"IDs of chats you sent a cursor for that you are no longer in (left, removed or deleted)"}},"description":"Changes to your chat list"},"events":{"type":"object","properties":{"6ad1d0a1c2b3a4f5e6d7c801":{"type":"object","properties":{"seq":{"type":"integer","description":"The chat's new cursor: send it for this chat next time"},"more":{"type":"boolean","description":"true when older changed messages were left out: load older history page by page"},"resync":{"type":"boolean","description":"true when the changes cannot be replayed: drop what you hold for this chat and reload it"},"messages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"chat":{"type":"string","description":"ID of the chat it is in"},"content":{"type":"string","description":"Its text"},"type":{"type":"string","description":"text, image, video, file, audio, call, location, system, poll, story_reply, interactive, notification or deleted"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions"},"reactions":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"userId":{"type":"string"},"emoji":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}},"description":"Emoji reactions (userId, emoji, createdAt)"},"medias":{"type":"array","description":"Files attached to it"},"edited":{"type":"boolean","description":"Whether it was edited"},"isDeleted":{"type":"boolean","description":"Whether it was deleted"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was stored"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"},"sender":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"profilePhoto":{"type":"string"},"type":{"type":"string"}},"description":"Who sent it (_id, name, profilePhoto address, type)"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who read it"}}},"description":"Messages that are new or changed, as they are now, oldest first"},"removedMessageIds":{"type":"array","items":{"type":"string"},"description":"IDs of changed messages that are gone"},"reads":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string"},"at":{"type":"string","format":"date-time"},"all":{"type":"boolean"}}},"description":"Read receipts, oldest first: who (userId), when (at), and which messages (messageIds) or all: true for everything up to then"},"threadReads":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string"},"at":{"type":"string","format":"date-time"},"rootId":{"type":"string"},"messageIds":{"type":"array","items":{"type":"string"}}}},"description":"Reads inside threads (userId, at, rootId of the thread, and messageIds or allInThread: true); absent when resync is true"}},"description":"One changed chat (the key is its ID)"}},"description":"What changed in each changed chat, keyed by chat ID"},"archives":{"type":"array","items":{"type":"object","properties":{"chatId":{"type":"string","description":"Chat ID"},"isArchived":{"type":"boolean","description":"Whether you have it archived now"},"archiveVersion":{"type":"integer","description":"How many times you archived or restored it; send it as expectedVersion next time"}}},"description":"Your archive state for every chat you ever archived or restored"}}},"example":{"success":true,"serverTime":"2026-10-16T09:31:00.000Z","partial":false,"chats":{"added":[{"_id":"6ad1d0a1c2b3a4f5e6d7c801","organizationId":"66a4b275003d1b495212b5aa","participants":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina@inet.africa","phone":"+254712345678","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","online":true,"lastSeen":"2026-10-16T08:55:00.000Z","inCall":false,"inCallKind":null},{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian@inet.africa","phone":"+254722334455","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","online":false,"lastSeen":"2026-10-16T07:40:00.000Z","inCall":false,"inCallKind":null}],"lastMessage":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian@inet.africa","phone":"+254722334455","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a"},"content":"The October fibre invoice is in, please approve by Friday.","type":"text","mentions":["66f1b2c3d4e5f60718293a4b"],"reactions":[{"_id":"6ad1d0b2c3d4e5f6a7b8c9f1","userId":"66f1b2c3d4e5f60718293a4b","emoji":"👍","createdAt":"2026-10-16T09:12:00.000Z"}],"medias":[],"edited":false,"isDeleted":false,"timestamp":"2026-10-16T09:10:00.000Z","createdAt":"2026-10-16T09:10:00.000Z","updatedAt":"2026-10-16T09:12:00.000Z","__v":0},"chatName":"Finance team","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","description":"Invoices, payments and month-end","isGroupChat":true,"groupAdmins":["66f1b2c3d4e5f60718293a4b"],"assistantAction":"assistant_tagged_reply","chatType":"chat","seq":42,"pinnedMessages":[{"_id":"6ad1d1c9d0e1f2a3b4c5d601","messageId":"6ad1d0b2c3d4e5f6a7b8c902","pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedAt":"2026-10-14T06:30:00.000Z","notifyMode":"notify"}],"createdAt":"2026-09-01T07:00:00.000Z","updatedAt":"2026-10-16T09:10:00.000Z","__v":3,"markedUnread":false,"isPinned":true,"pinnedAt":"2026-10-02T08:00:00.000Z","isArchived":false,"archiveVersion":0,"threadActivityAt":"2026-10-16T09:20:00.000Z","unreadMessagesCount":3,"unreadMentionsCount":1}],"updated":[{"_id":"6ad1d0a1c2b3a4f5e6d7c801","organizationId":"66a4b275003d1b495212b5aa","participants":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina@inet.africa","phone":"+254712345678","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","online":true,"lastSeen":"2026-10-16T08:55:00.000Z","inCall":false,"inCallKind":null},{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian@inet.africa","phone":"+254722334455","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","online":false,"lastSeen":"2026-10-16T07:40:00.000Z","inCall":false,"inCallKind":null}],"lastMessage":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian@inet.africa","phone":"+254722334455","type":"Human","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a"},"content":"The October fibre invoice is in, please approve by Friday.","type":"text","mentions":["66f1b2c3d4e5f60718293a4b"],"reactions":[{"_id":"6ad1d0b2c3d4e5f6a7b8c9f1","userId":"66f1b2c3d4e5f60718293a4b","emoji":"👍","createdAt":"2026-10-16T09:12:00.000Z"}],"medias":[],"edited":false,"isDeleted":false,"timestamp":"2026-10-16T09:10:00.000Z","createdAt":"2026-10-16T09:10:00.000Z","updatedAt":"2026-10-16T09:12:00.000Z","__v":0},"chatName":"Finance team","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","description":"Invoices, payments and month-end","isGroupChat":true,"groupAdmins":["66f1b2c3d4e5f60718293a4b"],"assistantAction":"assistant_tagged_reply","chatType":"chat","seq":42,"pinnedMessages":[{"_id":"6ad1d1c9d0e1f2a3b4c5d601","messageId":"6ad1d0b2c3d4e5f6a7b8c902","pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedAt":"2026-10-14T06:30:00.000Z","notifyMode":"notify"}],"createdAt":"2026-09-01T07:00:00.000Z","updatedAt":"2026-10-16T09:10:00.000Z","__v":3,"markedUnread":false,"isPinned":true,"pinnedAt":"2026-10-02T08:00:00.000Z","isArchived":false,"archiveVersion":0,"threadActivityAt":"2026-10-16T09:20:00.000Z","unreadMessagesCount":3,"unreadMentionsCount":1}],"removed":["6ad1d0a1c2b3a4f5e6d7c802"]},"events":{"6ad1d0a1c2b3a4f5e6d7c801":{"seq":42,"more":false,"resync":false,"messages":[{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","content":"The October fibre invoice is in, please approve by Friday.","type":"text","mentions":["66f1b2c3d4e5f60718293a4b"],"reactions":[{"_id":"6ad1d0b2c3d4e5f6a7b8c9f1","userId":"66f1b2c3d4e5f60718293a4b","emoji":"👍","createdAt":"2026-10-16T09:12:00.000Z"}],"medias":[],"edited":false,"isDeleted":false,"timestamp":"2026-10-16T09:10:00.000Z","createdAt":"2026-10-16T09:10:00.000Z","updatedAt":"2026-10-16T09:12:00.000Z","__v":0,"sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a5c/brian-2026-09-03_12-30-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","type":"Human"},"viewedBy":["66f1b2c3d4e5f60718293a4b"]}],"removedMessageIds":["6ad1d0b2c3d4e5f6a7b8c902"],"reads":[{"userId":"66f1b2c3d4e5f60718293a5c","at":"2026-10-16T09:15:00.000Z","all":true}],"threadReads":[{"userId":"66f1b2c3d4e5f60718293a5c","at":"2026-10-16T09:20:00.000Z","rootId":"6ad1d0c3d4e5f6a7b8c9da01","messageIds":["6ad1d0c3d4e5f6a7b8c9da02"]}]}},"archives":[{"chatId":"6ad1d0a1c2b3a4f5e6d7c801","isArchived":true,"archiveVersion":1}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.read","chat.messages.read"]}],"x-required-scopes":["chat.chats.read","chat.messages.read"],"x-scope-mode":"all"}},"/calendar":{"post":{"tags":["Meetings"],"summary":"Use my calendar","description":"Runs one Spaces calendar call for you from Chat: list, read, create, change or cancel events, answer invitations, and use an event's discussion, decisions and tasks. Spaces checks your own Spaces permissions and access to the event, and its reply (and its status) comes back as is. A 401 from Spaces comes back as 502, so it never signs you out of Chat.\n\n**Permission:** `chat.meetings.read` (View meetings).","operationId":"userCalendar","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"operation":{"type":"string","enum":["list","get","create","update","cancel","respond","resolve","people","retry","discussion","comment","actions","decide","withdraw","task","link","unlink","taskStatus","taskSearch"],"description":"Which calendar call to run, e.g. list for your events, get for one event, respond to answer an invitation","examples":["list"]},"payload":{"type":"object","description":"That calendar call's own inputs, as the Spaces API describes them, e.g. { startDate, endDate } for list or { eventId } for get. Defaults to none","examples":[{"startDate":"2026-10-19T00:00:00.000Z","endDate":"2026-10-26T00:00:00.000Z"}]}},"required":["operation"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Event ID"},"title":{"type":"string","description":"What the event is"},"startDate":{"type":"string","format":"date-time","description":"When it starts"},"endDate":{"type":"string","format":"date-time","description":"When it ends"},"allDay":{"type":"boolean","description":"Whether it takes the whole day"},"timeZone":{"type":"string","description":"IANA time zone it was planned in"},"meetingUrl":{"type":"string","description":"Link to join its call"},"creatorId":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"id":{"type":"string"}},"description":"The organizer (firstName, lastName, email, id)"},"attendees":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"},"email":{"type":"string"},"id":{"type":"string"}}},"status":{"type":"string"},"respondedAt":{"type":"string","format":"date-time"}}},"description":"Who is invited (userId: the person), their answer (status) and when they answered (respondedAt)"},"version":{"type":"integer","description":"The event's revision"}}},"description":"For list: your events (shown trimmed; the Spaces API lists every field)"}}},"example":{"events":[{"id":"6ad1d2e5f6a7b8c9d0e1f201","title":"October finance review","startDate":"2026-10-21T07:00:00.000Z","endDate":"2026-10-21T08:00:00.000Z","allDay":false,"timeZone":"Africa/Nairobi","meetingUrl":"https://chat.kazee.africa/?chat=6ad1d0a1c2b3a4f5e6d7c801&meeting=6ad1d2a1b2c3d4e5f6a7b801","creatorId":{"firstName":"Amina","lastName":"Wanjiru","email":"amina@inet.africa","id":"66f1b2c3d4e5f60718293a4b"},"attendees":[{"userId":{"firstName":"Brian","lastName":"Otieno","email":"brian@inet.africa","id":"66f1b2c3d4e5f60718293a5c"},"status":"accepted","respondedAt":"2026-10-16T08:12:00.000Z"}],"version":2}]}}}},"400":{"description":"operation is not one of the supported ones, or Spaces refused the inputs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You cannot use the calendar this way: a service or app token, a bot without its own bot token, or Spaces refused you that operation or event","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"},"502":{"description":"Spaces or Kazee sign-in refused Chat's own access","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"The calendar is unavailable; keep your changes and try again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.meetings.read"]}],"x-required-scopes":["chat.meetings.read"]}},"/attendance/checkin":{"post":{"tags":["Attendance"],"summary":"Check in","description":"Checks you in at work in Kazee People (HR Hub); Chat records it on your behalf. Any signed-in person may call it, always for themselves; HR Hub then checks you have attendance access. The answer is today's record.\n\n**Permission:** any signed-in member.","operationId":"attendanceCheckIn","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"location":{"type":"array","items":{"type":"number"},"description":"Where you are, as [latitude, longitude]; HR Hub checks it against your organisation's check-in areas if it has any. Leave it out when the device has no position; never send a made-up one","examples":[[-1.2921,36.8219]]},"timezone":{"type":"string","description":"Your time zone as an IANA name, passed to HR Hub to count your day in; when left out, HR Hub decides","examples":["Africa/Nairobi"]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"attendance":{"type":"object","properties":{"date":{"type":"string","description":"The day, e.g. 2026-10-16"},"attendanceState":{"type":"string","description":"HR Hub's state for today, e.g. checkedIn or checkedOut"},"timezone":{"type":"string","description":"The time zone the day is counted in"},"attendanceEntries":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the entry in HR Hub"},"checkInTime":{"type":"string","format":"date-time","description":"When you checked in"},"checkOutTime":{"description":"When you checked out; null while still checked in"}}},"description":"Each check-in of the day with its check-out, oldest first (at most 50)"}},"description":"Your attendance for today"}}},"example":{"success":true,"attendance":{"date":"2026-10-16","attendanceState":"checkedIn","timezone":"Africa/Nairobi","attendanceEntries":[{"_id":"6ad1d1daebfc0d1e2f3a4b01","checkInTime":"2026-10-16T05:02:00.000Z","checkOutTime":null}]}}}}},"400":{"description":"timezone is not a time zone name such as Africa/Nairobi, or location is not two numbers (code invalid)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are signed in as a bot or an app, not a person (code people_only, or no code for an app token); your account lacks HR Hub attendance access (code no_access); or HR Hub check-in is not set up for your organisation (code not_available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"You are already checked in (code already_checked_in)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"You are outside your organisation's check-in area (code outside_geofence), or it has check-in areas and no location was sent (code location_required, error says to turn on location)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls with the same sign-in in a minute (30 for the status, 10 for a check-in or out)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"502":{"description":"HR Hub refused Chat's own request; nothing was recorded (code unavailable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"HR Hub or Kazee sign-in did not answer; for a check-in or out it may or may not have been recorded, so check the status first (code unavailable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":[]}]}},"/attendance/checkout":{"post":{"tags":["Attendance"],"summary":"Check out","description":"Checks you out of work in Kazee People (HR Hub); Chat records it on your behalf. Any signed-in person may call it, always for themselves; HR Hub then checks you have attendance access. The answer is today's record.\n\n**Permission:** any signed-in member.","operationId":"attendanceCheckOut","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"location":{"type":"array","items":{"type":"number"},"description":"Where you are, as [latitude, longitude]; HR Hub checks it against your organisation's check-in areas if it has any. Leave it out when the device has no position; never send a made-up one","examples":[[-1.2921,36.8219]]},"timezone":{"type":"string","description":"Your time zone as an IANA name, passed to HR Hub to count your day in; when left out, HR Hub decides","examples":["Africa/Nairobi"]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"attendance":{"type":"object","properties":{"date":{"type":"string","description":"The day, e.g. 2026-10-16"},"attendanceState":{"type":"string","description":"HR Hub's state for today, e.g. checkedIn or checkedOut"},"timezone":{"type":"string","description":"The time zone the day is counted in"},"attendanceEntries":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"ID of the entry in HR Hub"},"checkInTime":{"type":"string","format":"date-time","description":"When you checked in"},"checkOutTime":{"type":"string","format":"date-time","description":"When you checked out; null while still checked in"}}},"description":"Each check-in of the day with its check-out, oldest first (at most 50)"}},"description":"Your attendance for today"}}},"example":{"success":true,"attendance":{"date":"2026-10-16","attendanceState":"checkedOut","timezone":"Africa/Nairobi","attendanceEntries":[{"_id":"6ad1d1daebfc0d1e2f3a4b01","checkInTime":"2026-10-16T05:02:00.000Z","checkOutTime":"2026-10-16T14:31:00.000Z"}]}}}}},"400":{"description":"timezone is not a time zone name such as Africa/Nairobi, or location is not two numbers (code invalid)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are signed in as a bot or an app, not a person (code people_only, or no code for an app token); your account lacks HR Hub attendance access (code no_access); or HR Hub check-in is not set up for your organisation (code not_available)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"You are not checked in (code not_checked_in)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"You are outside your organisation's check-in area (code outside_geofence), or it has check-in areas and no location was sent (code location_required, error says to turn on location)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many calls with the same sign-in in a minute (30 for the status, 10 for a check-in or out)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"502":{"description":"HR Hub refused Chat's own request; nothing was recorded (code unavailable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"HR Hub or Kazee sign-in did not answer; for a check-in or out it may or may not have been recorded, so check the status first (code unavailable)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":[]}]}},"/guest-meetings/{joinCode}/knock":{"post":{"tags":["Meetings"],"summary":"Ask to join a meeting as a guest","description":"For a guest with a guest link: asks the meeting's host to be let in. Needs no sign-in. Send the header Authorization: Guest <secret>, where the secret is 43 random letters, digits, - or _ that the guest's browser made for its knock and keeps; the same secret and name again return the same guest, so a retry is safe. Then keep calling guestMeetingAccess (at most 30 times a minute) until the host decides. The guest's request lasts 2 hours, and no longer than 4 hours after the meeting's start.\n\n**Sign-in:** not needed.","operationId":"knockGuestMeeting","parameters":[{"name":"joinCode","in":"path","required":true,"schema":{"type":"string"},"description":"The join code from the guest link (/meet/<join code>), 43 characters","example":"8Eazc9EJr7-wHkb2sc0aAKJWK5C-yBUmKk1-zzGMErE"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"The name the host will see, up to 80 characters","examples":["Joan Achieng"]}},"required":["name"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"guestId":{"type":"string","description":"ID of the guest"},"state":{"type":"string","description":"waiting until the host decides; denied or left when this secret knocked before and was turned away or left"}}},"example":{"success":true,"guestId":"6ad1d2c3d4e5f6a7b8c9d001","state":"waiting"}}}},"400":{"description":"name is empty, over 80 characters or holds < > or control characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The Guest header is missing or malformed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The host has locked guest entry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No meeting open to guests with that join code, or this secret already knocked under another name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"description":"Over 20 knocks on this meeting, or 1200 guest calls from one address, in a minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Guest meetings are switched off on this server, or it could not check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/guest-meetings/access":{"post":{"tags":["Meetings"],"summary":"Check my guest admission","description":"For a guest who knocked: tells them whether the host has let them in and, once they have, how to join the call. Needs no sign-in. Send the header Authorization: Guest <secret>, where the secret is 43 random letters, digits, - or _ that the guest's browser made for its knock and keeps. Each call while admitted keeps their place in the call for another 65 seconds; a place not renewed in time is lost.\n\n**Sign-in:** not needed.","operationId":"guestMeetingAccess","responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"state":{"type":"string","description":"admitted (let in: the rest of the reply is how to join), waiting (not let in yet; the reply also has locked and hostPresent), denied (turned away or removed) or left"},"name":{"type":"string","description":"The name the guest gave"},"callType":{"type":"string","description":"audio or video"},"roomId":{"type":"integer","description":"Number of the call's room on the call server"},"callAttemptId":{"type":"string","description":"ID of the running call"},"config":{"type":"object","properties":{"iceServers":{"type":"array","items":{"type":"object","properties":{"urls":{"type":"array","items":{"type":"string"}},"username":{"type":"string"},"credential":{"type":"string"}}},"description":"Relay servers for audio and video, valid for 5 minutes"},"iceCredentialsExpiresAt":{"type":"integer","description":"When the relay password stops working, in milliseconds since 1970"},"server":{"type":"string","description":"Address of the guest media server to connect to"},"janusToken":{"type":"string","description":"Pass for the media server, valid for 5 minutes"},"roomToken":{"type":"string","description":"Pass for the call's room (the same pass)"},"janusTokenExpiresAt":{"type":"integer","description":"When the pass stops working, in milliseconds since 1970"},"roomTokenExpiresAt":{"type":"integer","description":"Same as janusTokenExpiresAt"}},"description":"How to connect"}}},"example":{"success":true,"state":"admitted","name":"Joan Achieng","callType":"video","roomId":48213377,"callAttemptId":"ca-7f3a9e15b2d44c8e9f1a2d6b","config":{"iceServers":[{"urls":["turn:turn.kazee.africa:3478?transport=udp","turns:turn.kazee.africa:5349"],"username":"1792141500:9c41d2a77e0b5f3e8a6c1d2e4f5a6b7c","credential":"q1fJ7m0ZQ3oQ5wq9Zx2Yb8nR4sE="}],"iceCredentialsExpiresAt":1792141500000,"server":"wss://calls.kazee.africa/calling/guests/ws","janusToken":"kcm1.eyJ2ZXJzaW9uIjoxLCJhdWRpZW5jZSI6ImthemVlLWNhbGwtbWVkaWEifQ.Yk3x9Qe2Lm8Rt5Vw1Za4Nc7Pd0Sf6Gh3Jk2Xb9Mn1Qr","roomToken":"kcm1.eyJ2ZXJzaW9uIjoxLCJhdWRpZW5jZSI6ImthemVlLWNhbGwtbWVkaWEifQ.Yk3x9Qe2Lm8Rt5Vw1Za4Nc7Pd0Sf6Gh3Jk2Xb9Mn1Qr","janusTokenExpiresAt":1792141500000,"roomTokenExpiresAt":1792141500000}}}}},"401":{"description":"The Guest header is missing or malformed, or the guest's request has expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The meeting is no longer open to guests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The guest's place in the call ran out or was taken away","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Over 30 checks a minute for this guest, or 1200 guest calls from one address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Guest meetings are switched off on this server, or it could not check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/guest-meetings/leave":{"post":{"tags":["Meetings"],"summary":"Leave a meeting as a guest","description":"For a guest: leaves the meeting, giving up their place in the call or their request to join. Needs no sign-in. Send the header Authorization: Guest <secret>, where the secret is 43 random letters, digits, - or _ that the guest's browser made for its knock and keeps. To come back they knock again with a new secret.\n\n**Sign-in:** not needed.","operationId":"leaveGuestMeeting","responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"state":{"type":"string","description":"Always left"}}},"example":{"success":true,"state":"left"}}}},"401":{"description":"The Guest header is missing or malformed, or the guest's request has expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"The meeting is no longer open to guests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Over 1200 guest calls in a minute from one address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Guest meetings are switched off on this server, or it could not check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/meetings/{meetingId}/guests/settings":{"post":{"tags":["Meetings"],"summary":"Set a meeting's guest link","description":"For the meeting's host: switches the guest link on or off and locks or unlocks guest entry. The first time it is switched on, a join code is made, and it stays the same after that. Locking stops new guests asking to join and the host letting anyone in.\n\n**Permission:** `chat.meetings.update` (Reschedule meetings).","operationId":"configureGuestMeeting","parameters":[{"name":"meetingId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the meeting","example":"6ad1d2a1b2c3d4e5f6a7b801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean","description":"true switches the guest link on, false off. Must be a JSON true or false","examples":[true]},"locked":{"type":"boolean","description":"true locks guest entry, false unlocks it; left out, it stays as it is","examples":[false]}},"required":["enabled"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"enabled":{"type":"boolean","description":"Whether the guest link is switched on"},"locked":{"type":"boolean","description":"Whether guest entry is locked"},"joinPath":{"type":"string","description":"Path of the guest link, to put after the Chat web address; null while the link is off"}}},"example":{"success":true,"enabled":true,"locked":false,"joinPath":"/meet/8Eazc9EJr7-wHkb2sc0aAKJWK5C-yBUmKk1-zzGMErE"}}}},"400":{"description":"enabled or locked is not true or false","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are not the meeting's host, the call was made with a service or app token, or (when switching on) managed calling is not on for the organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No meeting with that ID in a conversation you are in, or it is cancelled or over","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The meeting changed at the same moment; read it again and retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Guest meetings are switched off on this server, or it could not check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.meetings.update"]}],"x-required-scopes":["chat.meetings.update"]}},"/meetings/{meetingId}/guests/{guestId}/decision":{"post":{"tags":["Meetings"],"summary":"Let a guest in or turn them away","description":"For the meeting's host: lets a waiting guest into the running call, or turns them away: deny and remove do the same, turning the guest away and taking away any place they hold in the call. A call holds at most 10 people, guests included; admitting a guest already in answers admitted again.\n\n**Permission:** `chat.meetings.update` (Reschedule meetings).","operationId":"decideGuestMeeting","parameters":[{"name":"meetingId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the meeting","example":"6ad1d2a1b2c3d4e5f6a7b801"},{"name":"guestId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the guest, from hostGuestLobby","example":"6ad1d2c3d4e5f6a7b8c9d001"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"decision":{"type":"string","enum":["admit","deny","remove"],"description":"admit lets them in; deny and remove turn them away and take away any place they hold","examples":["admit"]}},"required":["decision"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"state":{"type":"string","description":"admitted or denied"}}},"example":{"success":true,"state":"admitted"}}}},"400":{"description":"guestId is not a valid ID, or decision is not admit, deny or remove","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are not the meeting's host, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No meeting with that ID in a conversation you are in, or no waiting guest with that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"To admit: the call is not running, the guest link is off or locked, the call already has 10 people, or the call changed at the same moment","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"Guest meetings are switched off on this server, or it could not check","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.meetings.update"]}],"x-required-scopes":["chat.meetings.update"]}},"/meetings/{meetingId}/cancel":{"post":{"tags":["Meetings"],"summary":"Cancel a meeting","description":"Cancels an upcoming meeting and updates its card in the conversation. Only its organizer may, before it starts, or the Spaces calendar for any meeting. Cancelling a meeting that is already cancelled answers it again unchanged.\n\n**Permission:** `chat.meetings.delete` (Cancel meetings) or `chat.meetings.manage` (Manage meetings (integrations)).","operationId":"cancelMeeting","parameters":[{"name":"meetingId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the meeting","example":"6ad1d2a1b2c3d4e5f6a7b801"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"calendarRevision":{"type":"integer","description":"Only for the Spaces calendar, calling with its app token, with origin spaces and occurrenceId: the event's revision, so an older change never overwrites a newer one","examples":[3]},"occurrenceId":{"type":"string","description":"Only for the Spaces calendar, calling with its app token: the occurrence the change is for, <series ID>:<original start>","examples":["6ad1d2e5f6a7b8c9d0e1f201:2026-10-21T07:00:00.000Z"]},"origin":{"type":"string","enum":["spaces"],"description":"Only for the Spaces calendar, calling with its app token: spaces marks the change as coming from the calendar, so it is not sent back there. Ignored from people","examples":["spaces"]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"meeting":{"type":"object","properties":{"id":{"type":"string","description":"Meeting ID"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chatId":{"type":"string","description":"ID of the conversation it is held in"},"chat":{"type":"object","properties":{"id":{"type":"string","description":"Conversation ID"},"title":{"type":"string","description":"Its name"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"},"source":{"description":"What made it, e.g. spaces:event for a room made for a calendar event; null for an ordinary chat"},"sourceEntityId":{"description":"ID of that calendar event or space; null for an ordinary chat"}},"description":"That conversation; absent when it could not be read back"},"title":{"type":"string","description":"What the meeting is"},"description":{"type":"string","description":"Longer notes; empty when none"},"callType":{"type":"string","description":"audio or video"},"status":{"type":"string","description":"scheduled, started, ended or cancelled. While its attendees are being brought over from the calendar the meeting also carries readiness: syncing"},"startsAt":{"type":"string","format":"date-time","description":"When it starts"},"endsAt":{"type":"string","format":"date-time","description":"When it ends"},"timeZone":{"type":"string","description":"IANA time zone it was planned in"},"createdBy":{"type":"string","description":"ID of the organizer"},"participants":{"type":"array","items":{"type":"string"},"description":"IDs of the conversation's members; empty when the conversation could not be read back"},"origin":{"type":"string","description":"chat when it was scheduled in Chat, spaces when it came from the Spaces calendar"},"card":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the card message"},"published":{"type":"boolean","description":"Whether the card has been posted yet"}},"description":"The meeting's card in the conversation"},"guests":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Guest link switched on"},"locked":{"type":"boolean","description":"Guest entry locked: nobody new may ask to join"}},"description":"Whether people from outside may join through a guest link"},"calendarEvent":{"type":"object","properties":{"app":{"type":"string"},"eventId":{"type":"string"},"syncedAt":{"type":"string","format":"date-time"},"state":{"type":"string"}},"description":"The Spaces calendar event it is linked to (app, eventId, syncedAt, state synced or unavailable; one occurrence of a repeating event also has seriesId, originalStartDate and occurrenceId); null when it has none"},"links":{"type":"object","properties":{"web":{"type":"string","description":"Link that opens it in Kazee Chat on the web"},"android":{"type":"string","description":"Link that opens its card in the phone app"}},"description":"Where to open it"},"createdAt":{"type":"string","format":"date-time","description":"When it was scheduled"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"}},"description":"The meeting"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"meeting":{"id":"6ad1d2a1b2c3d4e5f6a7b801","organizationId":"66a4b275003d1b495212b5aa","chatId":"6ad1d0a1c2b3a4f5e6d7c801","chat":{"id":"6ad1d0a1c2b3a4f5e6d7c801","title":"Finance team","isGroupChat":true,"source":null,"sourceEntityId":null},"title":"October finance review","description":"Go through the October invoices and the cash forecast.","callType":"video","status":"cancelled","startsAt":"2026-10-21T07:00:00.000Z","endsAt":"2026-10-21T08:00:00.000Z","timeZone":"Africa/Nairobi","createdBy":"66f1b2c3d4e5f60718293a4b","participants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"origin":"chat","card":{"messageId":"6ad1d2a1b2c3d4e5f6a7b801","published":true},"guests":{"enabled":false,"locked":false},"calendarEvent":{"app":"spaces","eventId":"6ad1d2e5f6a7b8c9d0e1f201","syncedAt":"2026-10-16T08:00:04.000Z","state":"synced"},"links":{"web":"https://chat.kazee.africa/?chat=6ad1d0a1c2b3a4f5e6d7c801&meeting=6ad1d2a1b2c3d4e5f6a7b801","android":"kazeechat://chat/6ad1d0a1c2b3a4f5e6d7c801?scrollTo=6ad1d2a1b2c3d4e5f6a7b801"},"createdAt":"2026-10-16T08:00:00.000Z","updatedAt":"2026-10-16T08:00:04.000Z"},"success":true}}}},"400":{"description":"You are not the organizer, the meeting has already started or ended, or the calendar revision is not valid or is older than one already applied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No meeting with that ID in a conversation you are in","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.meetings.delete","chat.meetings.manage"]}],"x-required-scopes":["chat.meetings.delete","chat.meetings.manage"],"x-scope-mode":"any"}},"/meetings/{chatId}/recordings/start":{"post":{"tags":["Meetings"],"summary":"Start recording a call","description":"Asks the server to record a call you have joined, in a conversation you are in. It answers at once with the recording in status starting; recording begins shortly after and the saved file shows in the conversation's recordings. If the call is already being recorded, it answers that recording, and the same requestId again answers the same recording.\n\n**Permission:** `chat.calls.create` (Make calls) and `chat.media.create` (Upload media).","operationId":"startMeetingRecording","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the conversation the call is in","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"callAttemptId":{"type":"string","description":"ID of the running call attempt, up to 128 characters","examples":["ca-7f3a9e15b2d44c8e9f1a2d6b"]},"requestId":{"type":"string","description":"16 to 128 letters, digits, _ or -, unique to this request, so a retry returns the same recording","examples":["rec-2026-10-14-finance-0705"]}},"required":["callAttemptId","requestId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"recording":{"type":"object","properties":{"id":{"type":"string","description":"Recording ID"},"directCall":{"type":"boolean","description":"true for a one-to-one call, which only its two people may see"},"chatId":{"type":"string","description":"ID of the conversation the call was in"},"callAttemptId":{"type":"string","description":"ID of the call attempt that was recorded"},"roomId":{"type":"integer","description":"Number of the call's room on the call server"},"status":{"type":"string","description":"starting, recording, stopping, processing (being saved), ready or failed. A failed recording also carries error: why"},"startedBy":{"type":"string","description":"ID of the person who started it"},"meeting":{"description":"The scheduled meeting it was made in (id, title, startsAt, and calendarEvent with eventId and, for one occurrence of a repeating event, seriesId and originalStartDate, or null); null for a call that was not a scheduled meeting"}},"description":"The recording"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"recording":{"id":"6ad1d2b2c3d4e5f6a7b8c901","directCall":false,"chatId":"6ad1d0a1c2b3a4f5e6d7c801","callAttemptId":"ca-7f3a9e15b2d44c8e9f1a2d6b","roomId":48213377,"status":"starting","startedBy":"66f1b2c3d4e5f60718293a4b","meeting":null},"success":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"You are not in the conversation or have not joined the call, an input is not valid, recording is not available on this call or the organisation's storage is not ready, requestId was used for another call, or the call's previous recording is still being saved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.calls.create","chat.media.create"]}],"x-required-scopes":["chat.calls.create","chat.media.create"],"x-scope-mode":"all"}},"/meeting-recordings/{recordingId}/stop":{"post":{"tags":["Meetings"],"summary":"Stop recording a call","description":"Asks for a call recording to stop and be saved. Anyone in the call may, and so may the person who started it or (for a group call) a chat admin after leaving. It answers at once with status stopping; the file is then saved in the background and its status becomes ready. Stopping a recording that has already stopped changes nothing.\n\n**Permission:** `chat.calls.create` (Make calls).","operationId":"stopMeetingRecording","parameters":[{"name":"recordingId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the recording","example":"6ad1d2b2c3d4e5f6a7b8c901"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"recording":{"type":"object","properties":{"id":{"type":"string","description":"Recording ID"},"directCall":{"type":"boolean","description":"true for a one-to-one call, which only its two people may see"},"chatId":{"type":"string","description":"ID of the conversation the call was in"},"callAttemptId":{"type":"string","description":"ID of the call attempt that was recorded"},"roomId":{"type":"integer","description":"Number of the call's room on the call server"},"status":{"type":"string","description":"starting, recording, stopping, processing (being saved), ready or failed. A failed recording also carries error: why"},"startedBy":{"type":"string","description":"ID of the person who started it"},"startedAt":{"type":"string","format":"date-time","description":"When recording began; absent until it has"},"meeting":{"description":"The scheduled meeting it was made in (id, title, startsAt, and calendarEvent with eventId and, for one occurrence of a repeating event, seriesId and originalStartDate, or null); null for a call that was not a scheduled meeting"}},"description":"The recording"},"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"recording":{"id":"6ad1d2b2c3d4e5f6a7b8c901","directCall":false,"chatId":"6ad1d0a1c2b3a4f5e6d7c801","callAttemptId":"ca-7f3a9e15b2d44c8e9f1a2d6b","roomId":48213377,"status":"stopping","startedBy":"66f1b2c3d4e5f60718293a4b","startedAt":"2026-10-14T07:05:12.000Z","meeting":null},"success":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No recording with that ID you may see, you are no longer in its conversation, or you are not in the call and neither started the recording nor (for a group call) administer the chat","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.calls.create"]}],"x-required-scopes":["chat.calls.create"]}},"/chat":{"post":{"tags":["Chats"],"summary":"Create a chat","description":"Creates a direct chat, group or comment chat; the new chat's members see it appear live. For a direct chat (chatType chat, not a group, exactly two members) that already exists between the same two people, it returns that chat with existing: true and makes nothing new. A comment chat's reply also carries source, sourceEntityId and sourceEntityTitle. A chat or group with you as its only member is allowed, and each such call makes a new one. Creating a chat does not clear the 30-second cache of List my chats (getChats): that cache is in your own HTTP client, so a list fetched again within 30 seconds may not show the new chat yet; use this reply or the live update instead. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.chats.create` (Create chats).","operationId":"createChat","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assistantAction":{"type":"string","enum":["assistant_tagged_reply","assistant_passive","assistant_free_reply"],"description":"How bots answer in the chat: only when tagged or replied to, read everything and reply when they can help, or reply to everything. Defaults to assistant_tagged_reply","examples":["assistant_tagged_reply"]},"chatName":{"type":"string","description":"The chat's name","examples":["Finance team"]},"chatType":{"type":"string","enum":["chat","comment","notifications"],"description":"chat for a direct chat, group or channel; comment for the comment chat of a task or other item (needs source and sourceEntityId)","examples":["chat"]},"description":{"type":"string","description":"What the chat is for","examples":["Invoices, payments and month-end"]},"groupAdmin":{"type":"string","description":"The group's first admin. Required when isGroupChat is true (refused without it) and ignored otherwise, so the schema does not mark it required. A person or bot must give their own user ID (principal.id from GET /api/principal/me on Kazee sign-in); another Kazee app's service token may name any member","examples":["66f1b2c3d4e5f60718293a4b"]},"isGroupChat":{"type":"boolean","default":false,"description":"true to make a group; then groupAdmin is required too","examples":[true]},"participants":{"type":"object","properties":{"members":{"type":"array","items":{"type":"string"}}},"description":"The members, as { members: [user IDs] }, all from your organisation; at least one. Include yourself (principal.id from GET /api/principal/me on Kazee sign-in): you are not added for you, and a chat you are not in is refused. A chat with only you in it is allowed. App logins cannot be members (add them on the chat's apps list)","examples":[{"members":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"]}]},"profilePhoto":{"type":"object","description":"A photo already stored, as { minioPath, bucketName }. A plain address is refused. To upload a photo, use setChatProfilePhoto after creating the chat","examples":[{"minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa"}]},"source":{"type":"string","description":"For a comment chat: the app and kind of item it belongs to, as app:kind","examples":["spaces:task"]},"sourceEntityId":{"type":"string","description":"For a comment chat: ID of that item","examples":["6ad0a0b4d5c26de56de949d3"]},"sourceEntityTitle":{"type":"string","description":"For a comment chat: the item's title, used in notifications","examples":["Send the October invoice"]}},"required":["chatName","chatType","participants"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"chatId":{"type":"string","description":"ID of the new chat, or of the direct chat the two of you already have"},"participants":{"type":"array","items":{"type":"string"},"description":"IDs of the members"},"chatName":{"type":"string","description":"Its name"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"}},"description":"Its photo as stored, when one was given"},"description":{"type":"string","description":"What it is for, when given"},"isGroupChat":{"type":"boolean","description":"Whether it is a group"},"groupAdmins":{"type":"array","items":{"type":"string"},"description":"IDs of its admins (groups only)"},"chatType":{"type":"string","description":"chat, comment or notifications"}}},"example":{"success":true,"chatId":"6ad1d0a1c2b3a4f5e6d7c801","participants":["66f1b2c3d4e5f60718293a4b","66f1b2c3d4e5f60718293a5c"],"chatName":"Finance team","profilePhoto":{"minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa"},"description":"Invoices, payments and month-end","isGroupChat":true,"groupAdmins":["66f1b2c3d4e5f60718293a4b"],"chatType":"chat"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"A personal assistant on its fixed chat rights may start only the direct chat with its owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: you are not one of the members, a member is not in your organisation or is an app login, groupAdmin is not you, a group has no groupAdmin, a comment chat has no source or sourceEntityId, participants is not { members: [...] }, chatType is unknown, or a value is not valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.create"]}],"x-required-scopes":["chat.chats.create"]}},"/chat/{chatId}/read":{"post":{"tags":["Chats"],"summary":"Mark a chat as read","description":"Marks every message from others in a chat as read by you, except replies that stay inside a thread (opening the thread reads those). When it marks any, the chat's members get read receipts live. Your other devices clear that chat's phone notifications, and your own unread marker on the chat is cleared.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"markChatAsRead","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"messagesUpdated":{"type":"integer","description":"How many messages this call marked as read"},"messageIds":{"type":"array","items":{"type":"string"},"description":"IDs of those messages; empty when there was nothing new to read"}}},"example":{"success":true,"messagesUpdated":2,"messageIds":["6ad1d0b2c3d4e5f6a7b8c901","6ad1d0b2c3d4e5f6a7b8c902"]}}}},"400":{"description":"chatId or userId is empty","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, you are not a member of the chat, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"chatId is not a valid ID, or the chat could not be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/thread/{chatId}/{rootId}/read":{"post":{"tags":["Threads"],"summary":"Mark a thread as read","description":"Marks every reply in a thread read for you; marking the chat read never reads thread replies. The chat's members see the read ticks live. rootId may be the root or any reply in the thread.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"markThreadAsRead","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"rootId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the thread's root, or of any reply in it","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"messageIds":{"type":"array","items":{"type":"string"},"description":"IDs of the replies this marked read; empty when there were none"},"unreadThreadCount":{"type":"integer","description":"How many followed threads you have not closed still have unread replies (the Threads badge)"}}},"example":{"success":true,"messageIds":["6ad1d0b2c3d4e5f6a7b8c902"],"unreadThreadCount":2}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of, or no thread with that ID in it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/thread/{chatId}/{rootId}/follow":{"post":{"tags":["Threads"],"summary":"Follow or unfollow a thread","description":"Follows or unfollows a thread for you: followers get a push notification for each reply and see the thread in their Threads view. Replying in it, or being mentioned in it, makes you follow it again. Your other devices see the change live.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"setThreadFollow","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"rootId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the thread's root, or of any reply in it","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"following":{"type":"boolean","description":"true (or \"true\") to follow; anything else unfollows","examples":[false]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["following","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"following":{"type":"boolean","description":"Whether you follow it now"}}},"example":{"success":true,"following":false}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of, or no thread with that ID in it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/thread/{chatId}/{rootId}/archive":{"post":{"tags":["Threads"],"summary":"Close or reopen a thread","description":"Closes (archives) a thread for you only, or reopens it: a closed thread leaves your Following and All lists and your unread badges and shows under the archived filter. Following it is not changed. The next reply in the thread reopens it for everyone who closed it. Your other devices see the change live.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"setThreadArchived","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"rootId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the thread's root, or of any reply in it","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean","description":"true to close it, false to reopen it (\"true\" and \"false\" also work)","examples":[true]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["archived","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"archived":{"type":"boolean","description":"Whether you have it closed now"}}},"example":{"success":true,"archived":true}}}},"400":{"description":"archived is not true or false","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of, or no thread with that ID in it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/thread/{chatId}/{rootId}/title":{"post":{"tags":["Threads"],"summary":"Name a thread","description":"Names a thread for everyone in the chat, or clears its name (apps then show the root's first line). Any member of the chat may, people and bots alike; with onlyIfUnset a bot names it only while it has no name, so it never overwrites a person's. Everyone in the chat sees the new name live, and a thread started on purpose has its header text changed to match (bots in the chat are not sent that edit).\n\n**Permission:** `chat.messages.create` (Send messages).","operationId":"setThreadTitle","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"rootId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the thread's root, or of any reply in it","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"onlyIfUnset":{"type":"boolean","description":"true to name it only if it has no name yet (for bots). Defaults to false","examples":[false]},"title":{"type":"string","description":"The name, up to 80 characters; runs of spaces and new lines become one space. Send an empty title (or null) to clear the name. Leaving it out is refused","examples":["October invoice"]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"changed":{"type":"boolean","description":"Whether the name changed (false when it was already that, or onlyIfUnset found a name)"},"title":{"type":"string","description":"The thread's name now; null when it has none"}}},"example":{"success":true,"changed":true,"title":"October invoice"}}}},"400":{"description":"title was not sent, is not text or is over 80 characters, or onlyIfUnset is not true or false","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of, or no thread with that ID in it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.create"]}],"x-required-scopes":["chat.messages.create"]}},"/thread/{chatId}/start":{"post":{"tags":["Threads"],"summary":"Start a thread","description":"Starts a new thread in a chat you are a member of: posts a header in the chat (\"🧵 <title>\", or \"🧵 New thread\" without one) and answers with it as the thread's root, which you follow. Send the first message with Send a message, threadRootId set to the header's _id. The header reaches every member live except the chat's bots, and nobody gets a push notification for it.\n\n**Permission:** `chat.messages.create` (Send messages).","operationId":"startThread","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"title":{"type":"string","description":"The thread's name, up to 80 characters; runs of spaces and new lines become one space. Blank means none","examples":["October invoice"]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"string","description":"A string: a signed link to their photo (the small copy when there is one), valid for a limited time; null if it could not be signed, absent when they have none. Calls that answer with a message as saved (Send a message, List a chat's pinned messages) give an object saying where it is stored instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The header's text: 🧵 and the thread's name, or 🧵 New thread without one"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","description":"Always empty: a header has no files"},"viewedBy":{"type":"array","description":"IDs of the people who have read it; empty for a new thread"},"mentions":{"type":"array","description":"Always empty"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","description":"Emoji reactions to it; empty for a new thread"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"},"threadStart":{"type":"boolean","description":"Always true: a thread started on purpose, listed before its first reply"},"threadReplyCount":{"type":"integer","description":"0: no replies yet"},"threadLastReplyAt":{"type":"string","format":"date-time","description":"When it was started, until the first reply"},"threadTitle":{"type":"string","description":"The thread's name; null when it has none (apps then show the root's first line)"},"threadTitleBy":{"type":"string","description":"ID of who named it; absent when it has no name"},"threadTitleAt":{"type":"string","format":"date-time","description":"When it was named; absent when it has no name"}},"description":"The thread's header, a root with no replies yet"}}},"example":{"success":true,"message":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=5d7e4c1a9b2f","type":"Human"},"content":"🧵 October invoice","status":"delivered","type":"text","interactive":{"buttons":[]},"medias":[],"viewedBy":[],"mentions":[],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"reactions":[],"timestamp":"2026-10-16T05:12:03.000Z","createdAt":"2026-10-16T05:12:03.000Z","updatedAt":"2026-10-16T05:12:03.000Z","__v":0,"threadStart":true,"threadReplyCount":0,"threadLastReplyAt":"2026-10-16T05:12:03.000Z","threadTitle":"October invoice","threadTitleBy":"66f1b2c3d4e5f60718293a4b","threadTitleAt":"2026-10-16T05:12:03.000Z"}}}}},"400":{"description":"title is not text or is over 80 characters, chatId is not a valid ID, or the chat has no threads (comment and notifications chats)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, the call was made with a service or app token, or you are not a member of the chat","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.messages.create"]}],"x-required-scopes":["chat.messages.create"]}},"/chat/{chatId}/unread":{"post":{"tags":["Chats"],"summary":"Mark a chat as unread","description":"Flags a chat as unread in your own chat list. Only the flag changes: messages keep their read state, and nobody else sees it. Your other devices pick it up on their next sync, and marking the chat as read clears it.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"markChatAsUnread","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"markedUnread":{"type":"boolean","description":"Always true: the chat now shows as unread for you"}}},"example":{"success":true,"markedUnread":true}}}},"400":{"description":"chatId or userId is empty","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, you are not a member of the chat, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"chatId is not a valid ID, or the chat could not be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/chat/{chatId}/pin":{"post":{"tags":["Chats"],"summary":"Pin a chat to the top of my list","description":"Pins a chat to the top of your own chat list, or unpins it. Only your list changes; other members see nothing. Your other devices pick it up on their next sync. To pin a chat inside one of your folders, use toggleChatPin.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"setChatPinned","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"pinned":{"type":"boolean","description":"true (or the text \"true\") to pin; anything else unpins","examples":[true]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["pinned","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"pinned":{"type":"boolean","description":"Whether the chat is now pinned for you"}}},"example":{"success":true,"pinned":true}}}},"400":{"description":"chatId or userId is empty","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, you are not a member of the chat, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"chatId is not a valid ID, or the chat could not be updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/chat/{chatId}/archive":{"post":{"tags":["Chats"],"summary":"Archive a chat","description":"Archives a chat in your own chat list, or restores it. Only your list changes: you stay a member and keep its messages. Send the archiveVersion you last saw as expectedVersion, so a change made on another device is not undone; asking for the state the chat is already in succeeds without that check. Your other devices get the change live and on their next sync.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"setChatArchived","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"archived":{"type":"boolean","description":"true to archive, false to restore (a JSON true or false, not text)","examples":[true]},"expectedVersion":{"type":"integer","minimum":0,"description":"The chat's archiveVersion as you last saw it (from the chat list, getChat or syncChanges); 0 if never archived","examples":[0]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); when sent, it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["archived","expectedVersion"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"archive":{"type":"object","properties":{"chatId":{"type":"string","description":"Chat ID"},"isArchived":{"type":"boolean","description":"Whether you have it archived now"},"archiveVersion":{"type":"integer","description":"How many times you archived or restored it; send it as expectedVersion next time"}},"description":"Your archive state for the chat now"}}},"example":{"success":true,"archive":{"chatId":"6ad1d0a1c2b3a4f5e6d7c801","isArchived":true,"archiveVersion":1}}}}},"400":{"description":"chatId is not a valid ID, archived is not true or false, or expectedVersion is not a whole number of 0 or more","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"expectedVersion is not the current archiveVersion: the state changed on another device; refresh and try again","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/chat/media/{chatId}":{"post":{"tags":["Media & files"],"summary":"Upload files to a chat","description":"Stores one or more files for a chat and answers with them, so they can be sent in a message. Send it as a form upload; each file may be up to 200 MB. Pictures, videos and office documents also get a small preview. If only some files fail, the call still succeeds and lists the failures in errors. You must be a member of the chat.\n\n**Permission:** `chat.media.create` (Upload media).","operationId":"uploadMedia","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat the files are for","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"height":{"type":"integer","description":"Height of the picture or video in pixels; ignored unless above 0","examples":[4032]},"media":{"type":"string","format":"binary","description":"The file. Repeat the field to send several in one call"},"thumbHash":{"type":"string","description":"A tiny blurred placeholder of the picture, kept so others see it while the file loads","examples":["1QcSHQRnh493V4dIh4eXh1h4kJUI"]},"width":{"type":"integer","description":"Width of the picture or video in pixels; ignored unless above 0","examples":[3024]}},"required":["media"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"true when at least one file was stored"},"message":{"type":"string","description":"How many of the files were stored"},"media":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"File ID"},"organizationId":{"type":"string","description":"Organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it was uploaded to"},"url":{"type":"string","description":"Address to download it, valid for 7 days"},"type":{"type":"string","description":"image, video or file (anything that is not a picture or video, voice notes included)"},"bucketName":{"type":"string","description":"Which store holds it"},"fileName":{"type":"string","description":"Name of the file as it was uploaded"},"minioPath":{"type":"string","description":"Where it is stored: chat/<chat ID>/<name>-<upload time>.<extension>"},"thumbHash":{"type":"string","description":"The small blurred placeholder the sender sent; absent when none was sent"},"width":{"type":"integer","description":"Width in pixels the sender sent; absent when none was sent"},"height":{"type":"integer","description":"Height in pixels the sender sent; absent when none was sent"},"thumbnail":{"type":"object","properties":{"url":{"type":"string","description":"Address to download the preview, valid for 7 days"},"minioPath":{"type":"string","description":"Where the preview is stored"},"bucketName":{"type":"string","description":"Which store holds the preview"},"width":{"type":"integer","description":"Preview width in pixels"},"height":{"type":"integer","description":"Preview height in pixels"}},"description":"Preview made at upload: a JPEG at most 640 pixels on its long side for a picture or office document, the first frame for a video (no width or height then). Absent when none could be made"},"createdAt":{"type":"string","format":"date-time","description":"When it was uploaded"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}}},"description":"The stored files, to attach to a message by their IDs"},"errors":{"type":"array","items":{"type":"object","properties":{"fileName":{"type":"string","description":"Name of the file that failed"},"error":{"type":"string","description":"Why it failed"}}},"description":"Only when some files failed: each failed file's fileName and error"}}},"example":{"success":true,"message":"1 of 2 media uploaded successfully","media":[{"_id":"6ad1d0d4e5f6a7b8c9dae101","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-2026-10-16_09-20-00.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","type":"image","bucketName":"org-66a4b275003d1b495212b5aa","fileName":"site-visit.jpg","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-2026-10-16_09-20-00.jpg","thumbHash":"1QcSHQRnh493V4dIh4eXh1h4kJUI","width":3024,"height":4032,"thumbnail":{"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-thumb-2026-10-16_09-20-01.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/site-visit-thumb-2026-10-16_09-20-01.jpg","bucketName":"org-66a4b275003d1b495212b5aa","width":480,"height":640},"createdAt":"2026-10-16T06:20:01.000Z","updatedAt":"2026-10-16T06:20:01.000Z","__v":0}],"errors":[{"fileName":"scan.heic","error":"Upload failed"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No chat has that ID or you are not in it, chatId is not a valid ID, or every file failed to store (the reply then lists them in errors)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.media.create"]}],"x-required-scopes":["chat.media.create"]}},"/user/{userId}/profile-photo":{"post":{"tags":["People"],"summary":"Change my profile photo","description":"Uploads a new profile photo for you, as multipart form data, and makes a 256-pixel version for small avatars. It replaces your photo for everyone; the old file is kept. You can only change your own photo.\n\n**Permission:** `chat.users.update` (Update own profile).","operationId":"setProfilePhoto","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"photo":{"type":"string","format":"binary","description":"The picture (any image type), at most 200 MB"}},"required":["photo"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"Always \"Profile photo updated successfully\""},"profilePhoto":{"type":"object","properties":{"url":{"type":"string","description":"Link to the full photo, valid 7 days without sign-in"},"minioPath":{"type":"string","description":"Where the full photo is stored"},"bucketName":{"type":"string","description":"Which store holds it"},"thumbUrl":{"type":"string","description":"Link to the 256-pixel version, valid 7 days; null if it could not be made"},"thumbMinioPath":{"type":"string","description":"Where the 256-pixel version is stored; null if it could not be made"},"thumbBucketName":{"type":"string","description":"Which store holds it; null if it could not be made"}},"description":"The new photo"}}},"example":{"success":true,"message":"Profile photo updated successfully","profilePhoto":{"url":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","minioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbUrl":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","thumbMinioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No photo was sent, the file is not a picture, or it could not be stored; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.update"]}],"x-required-scopes":["chat.users.update"]}},"/chat/{chatId}/profile-photo":{"post":{"tags":["Chats"],"summary":"Set a chat's photo","description":"Uploads a new photo for a chat, sent as a multipart form upload, and makes a 256-pixel copy for chat lists. In a group only an admin may change it; in other chats any member may. Members see the new photo when they next load the chat; no live update is sent. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"setChatProfilePhoto","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"photo":{"type":"string","format":"binary","description":"The image file (JPEG, PNG or another image type, checked from the file's content)","examples":["finance-team.jpg"]},"requesterId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["photo","requesterId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"A confirmation sentence"},"profilePhoto":{"type":"object","properties":{"url":{"type":"string","description":"Address to download the photo; it works for up to 7 days"},"minioPath":{"type":"string","description":"Where the photo is stored"},"bucketName":{"type":"string","description":"Which store holds it"},"thumbUrl":{"type":"string","description":"Address of its 256-pixel copy, or null when the copy could not be made"},"thumbMinioPath":{"type":"string","description":"Where that copy is stored, or null"},"thumbBucketName":{"type":"string","description":"Which store holds that copy, or null"}},"description":"The new photo"}}},"example":{"success":true,"message":"Chat profile photo updated successfully","profilePhoto":{"url":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","minioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbUrl":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=7b2e4f901c3a4d5e","thumbMinioPath":"chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"requesterId is not the signed-in person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: no chat with that ID, you are not a member, the chat is a group and you are not one of its admins, no photo was sent, the file is not an image, the upload failed, or chatId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/chat/{chatId}/apps/{appKey}/launch":{"post":{"tags":["Apps"],"summary":"Open a bot's app","description":"Opens one of a bot's apps from your direct chat with that bot: gives the app's address and a one-time launch pass, good for one minute, that the app's server swaps with redeemAppPass for who you are, which chat and which bot. Only people may call it, and only in a direct chat they are in; there is no separate permission. A refusal answers success false and a short error code.\n\n**Permission:** any signed-in member.","operationId":"launchBotApp","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of your direct chat with the bot","example":"6ad1d0a1c2b3a4f5e6d7c802"},{"name":"appKey","in":"path","required":true,"schema":{"type":"string"},"description":"Key of the app, as getBotApps lists it","example":"browser"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"url":{"type":"string","description":"Address of the app's page to open"},"pass":{"type":"string","description":"The launch pass to hand to that page: works once, within expiresIn seconds"},"expiresIn":{"type":"integer","description":"Seconds the pass stays good: 60"}}},"example":{"success":true,"url":"https://api.agentspace.kazee.africa/api/apps/browser","pass":"g6_T1RWhyRqV8248LBN0s-OXV-b61Ch5uC_fLfKmQCQ","expiresIn":60}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"people-only: a bot or app token called it; or direct-chats-only: the chat is a group, channel or other kind of room","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"chat-not-found: no chat with that ID that you are in; or app-not-found: the other person is not an active bot, it offers no app with that key, or the app's address is no longer allowed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"description":"rate-limited: over 30 launches in a minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"unavailable: the pass could not be made","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":[]}]}},"/apps/passes/redeem":{"post":{"tags":["Apps"],"summary":"Redeem an app launch pass","description":"For a bot app's server: swaps a launch pass from launchBotApp for who opened the app, from which chat and with which bot. Needs no sign-in, because the pass is the credential. A pass works once and only within a minute of being made; the reply is never cached and does not echo the pass back.\n\n**Sign-in:** not needed.","operationId":"redeemAppPass","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"pass":{"type":"string","description":"The launch pass, 43 characters. Without it the call answers 404","examples":["g6_T1RWhyRqV8248LBN0s-OXV-b61Ch5uC_fLfKmQCQ"]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"organizationId":{"type":"string","description":"Organisation of the person who opened the app"},"userId":{"type":"string","description":"ID of that person"},"userName":{"type":"string","description":"Their name; empty when it is not known"},"chatId":{"type":"string","description":"ID of their direct chat with the bot, where they opened it"},"botUserId":{"type":"string","description":"ID of the bot"},"appKey":{"type":"string","description":"Key of the app they opened"},"appUrl":{"type":"string","description":"Address of the app's page, as the bot registered it"}}},"example":{"success":true,"organizationId":"66a4b275003d1b495212b5aa","userId":"66f1b2c3d4e5f60718293a4b","userName":"Amina Wanjiru","chatId":"6ad1d0a1c2b3a4f5e6d7c802","botUserId":"6ad1d0f6a7b8c9daebfc0301","appKey":"browser","appUrl":"https://api.agentspace.kazee.africa/api/apps/browser"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"404":{"description":"invalid-or-expired: the pass is missing, malformed, already used or over a minute old","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"description":"rate-limited: over 600 tries in a minute from one address","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"unavailable: the pass could not be checked","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[]}},"/message/{id}/view/open":{"post":{"tags":["Messages"],"summary":"Open a bot's HTML view","description":"Opens the page of a bot's view card (a card with a view block): gives an address on the views host with a one-time pass in it, good for one minute. Any person or bot in the message's chat may call it; there is no separate permission. Show the address in a sandboxed frame. A refusal answers success false and a short error code.\n\n**Permission:** any signed-in member.","operationId":"openHtmlView","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the view card's message","example":"6ad1d0b2c3d4e5f6a7b8c901"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"url":{"type":"string","description":"Address of the page on the views host, with a one-time pass in it: works once, within expiresIn seconds"},"expiresIn":{"type":"integer","description":"Seconds the address stays good: 60"}}},"example":{"success":true,"url":"https://views.kazee.africa/api/view-page/g6_T1RWhyRqV8248LBN0s-OXV-b61Ch5uC_fLfKmQCQ","expiresIn":60}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"forbidden: an app-to-app service token or an app login called it, or the sign-in is for another organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"message-not-found: no message with that ID in a chat you are in, or it was deleted; or not-a-view: the message carries no view card","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"429":{"description":"rate-limited: over 30 opens in a minute","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"500":{"$ref":"#/components/responses/ServerError"},"503":{"description":"unavailable: the pass could not be made","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":[]}]}},"/chat/{chat_id}/message":{"post":{"tags":["Messages"],"summary":"Send a message","description":"Posts a message in a chat and answers with status 201 and the saved message. A person, bot or other Kazee app posts as a sender who is a member of the chat; an outside system's app login posts plain text, optionally in a thread, as itself and only in channels whose Apps list it is on. Everyone in the chat gets the message live; the other members (for a reply that stays in its thread, the thread's followers) get a push notification, people mentioned get a mention notification, and the first link in a text message gets a preview a moment later. Only a bot, with its own token, may send a card.\n\n**Permission:** `chat.messages.create` (Send messages).","operationId":"sendMessage","parameters":[{"name":"chat_id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat to post in. This route spells it chat_id; most Chat routes call the same ID chatId","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"alsoInChannel":{"type":"boolean","description":"With threadRootId: true also shows the reply in the chat itself (\"Also send to channel\"). Ignored without threadRootId","examples":[false]},"card":{"type":"object","description":"A Kazee Card, bots only and only with the bot's own token: an object, or the same as JSON text, of at most 16 KB. v is 1, 2, 3 or 4 (the server sets it: 4 with a view block, 3 with a link block, 2 with other building blocks); kind is decision, choice, rating, slider, report or form; title (up to 140 characters) is required, and kicker, tag, body, footer, blocks, extras, recommendation and open are optional. input is what people answer (options for decision and choice, max for rating, min, max and step for slider, fields for a form; none for a report). policy says who may answer (responders: \"anyone\" or up to 200 user IDs), how (mode: first, each or changeable), when results show (results: live, closed or hidden), whether answers are anonymous and when it closes (closesAt). The server checks it, sets v and a fresh state, and stores the message as interactive with buttons older apps can press (or as text)","examples":[{"v":1,"kind":"decision","title":"Approve the October payment run?","body":"12 suppliers, KES 1,240,000 in total.","input":{"options":[{"id":"approve","label":"Approve","style":"primary"},{"id":"hold","label":"Hold","style":"danger"}]},"policy":{"responders":["66f1b2c3d4e5f60718293a4b"],"mode":"first"}}]},"content":{"type":"string","description":"The text, or the caption of a photo, video, file or voice note. Required for a text message (400 without it) unless you send a card; other types may leave it out, but a message with no content, files or location is not saved. Mention someone by writing @[Name](userId) in it; @[All](all) mentions everyone in the chat, except in a reply that stays in its thread. With a card it defaults to a plain-text version of the card, which older apps show","examples":["Payment of KES 184,000 from Westlands Mall received. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) please match it to the October invoice."]},"findMeCode":{"type":"string","description":"A code of your own, for example a UUID. It is stored on the message and comes back in the reply and in the live update, so you can match the message to your request","examples":["c3d0b9e2-7f41-4b1a"]},"interactive":{"type":"object","properties":{"buttons":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"style":{"type":"string","enum":["primary","secondary","danger"]},"payload":{}}}}},"description":"For an interactive message: its buttons. id tells you which button was pressed, label is what it says, style is primary, secondary or danger, and payload is any data you want back with the press. Presses only work on a bot's message: each goes to that bot as a live event. Send content as well, or the message is not saved. Ignored when you send a card","examples":[{"buttons":[{"id":"matched","label":"Matched","style":"primary","payload":{"invoice":"INV-2026-1043"}},{"id":"query","label":"Query it","style":"secondary"}]}]},"location":{"type":"object","properties":{"latitude":{"type":"number"},"longitude":{"type":"number"}},"description":"For a location message: the place, in decimal degrees","examples":[{"latitude":-1.2676,"longitude":36.8108}]},"media_id":{"type":"string","description":"ID of a file already uploaded (uploadMedia, POST /chat/media/:chatId), for an image, video, file or audio message. Ignored for other types","examples":["6ad1d0d4e5f6a7b8c9dae101"]},"media_ids":{"type":"array","items":{"type":"string"},"description":"IDs of several uploaded files for one message, in order; used instead of media_id when both are sent (a single ID also works). Ignored for other types than image, video, file and audio","examples":[["6ad1d0d4e5f6a7b8c9dae101"]]},"media_url":{"type":"string","description":"Old way to attach a file by its link, for image, video, file and audio messages. The file record it makes lacks fields the server requires, so it answers 500: upload the file to the chat first and pass media_id instead","examples":["https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/statement-october.pdf"]},"mentions":{"type":"array","items":{"type":"string"},"description":"Not used: the server finds mentions in content (@[Name](userId)) and ignores this list","examples":[["66f1b2c3d4e5f60718293a5c"]]},"replyTo":{"type":"string","description":"ID of the message this one replies to, from this chat or another chat you are in; the reply comes back with that message filled in. A message outside your chats is dropped and the reply sends without it","examples":["6ad1d0b2c3d4e5f6a7b8c902"]},"replyToMediaId":{"type":"string","description":"With replyTo: the ID of one file in that message, to reply to just that file","examples":["6ad1d0d4e5f6a7b8c9dae101"]},"sender":{"type":"string","description":"Required, except with an app login: an app login always posts as itself and may leave it out, so the schema cannot mark it required; left out by anyone else, the call answers 400. A person gives their own user ID (principal.id from GET /api/principal/me on Kazee sign-in) and a bot its own ID; another Kazee app's service token may name any member. A person or bot naming someone else is refused with 403 where the server enforces it, and only logged where it does not","examples":["6ad1d0f6a7b8c9daebfc0301"]},"threadRootId":{"type":"string","description":"Reply in a thread: the ID of the thread's root or of any reply in it (threads are one level deep). It must be a message in this chat, in an ordinary chat (not a comment or notifications chat), and not a system or notification message or a deleted one without replies. The reply stays out of the chat's timeline, unread count and preview unless alsoInChannel is true, and only the thread's followers are notified. Replying, or being mentioned in a reply, makes you a follower","examples":["6ad1d0b2c3d4e5f6a7b8c901"]},"type":{"type":"string","enum":["text","image","video","file","audio","location","interactive","poll","call","story_reply","system","notification","deleted"],"description":"Kind of message: text, image, video, file, audio (a voice note), location or interactive (with buttons). call, notification and deleted are Chat's own records and are refused. An app login may send text only. With a card the server sets the type itself (interactive or text)","examples":["text"]}},"required":["type"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"object","properties":{"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"findMeCode":{"type":"string","description":"Your findMeCode, sent back so you can match the reply to your request; absent if you sent none"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}},"description":"An object, not a link: where their photo is stored (minioPath and bucketName, and the small copy's thumbMinioPath and thumbBucketName); absent when they have none. Calls that read messages (List a chat's messages, Read a thread) give a signed link string instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","description":"Files attached to it (empty for a text message): each as listed under Read a thread or List a chat's messages"},"viewedBy":{"type":"array","description":"IDs of the people who have read it; empty for a new message"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions (everyone in the chat for @all)"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"_id":{"type":"string","description":"Message ID"},"reactions":{"type":"array","description":"Emoji reactions to it; empty for a new message"},"editHistory":{"type":"array","description":"Earlier versions of the text; empty for a new message"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"}},"description":"The saved message, as everyone in the chat receives it. Keys only some messages carry appear only when set: replyTo (the quoted message, filled in with its sender and files), replyToMediaId, replyToChat and replyToChatName, threadRoot and alsoInChannel (a thread reply), threadReplyCount, threadLastReplyAt, threadParticipants, threadTitle, threadTitleBy, threadTitleAt and threadStart (a thread's root), location, linkPreview, card (a bot's Kazee Card with its public state, plus your own answer as card.mine), forwardedFrom, storyRef, systemData, editedAt, deletedAt and findMeCode. If the server could not save it (for example an unknown type, or a mention whose ID is not a user ID), this is instead your request echoed back with receivedAt, still with status 201"}}},"example":{"success":true,"message":{"organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","findMeCode":"c3d0b9e2-7f41-4b1a","sender":{"_id":"6ad1d0f6a7b8c9daebfc0301","name":"Finance Bot","profilePhoto":{"minioPath":"chat/profiles/6ad1d0f6a7b8c9daebfc0301/finance-bot-2026-08-20_09-00-00.png","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profiles/6ad1d0f6a7b8c9daebfc0301/finance-bot-2026-08-20_09-00-00-thumb.png","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"type":"AI"},"content":"Payment of KES 184,000 from Westlands Mall received. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) please match it to the October invoice.","status":"delivered","type":"text","interactive":{"buttons":[]},"medias":[],"viewedBy":[],"mentions":["66f1b2c3d4e5f60718293a5c"],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"_id":"6ad1d0b2c3d4e5f6a7b8c901","reactions":[],"editHistory":[],"timestamp":"2026-10-16T05:12:03.000Z","createdAt":"2026-10-16T05:12:03.000Z","updatedAt":"2026-10-16T05:12:03.000Z","__v":0}}}}},"400":{"description":"sender is missing (only an app login may leave it out); an app login sent anything but plain text; threadRootId is not a thread this chat can reply in; the card is not valid (a view block's page is not an .html file of this chat, or its preview not an image of this chat, counts too); a text message has no content; an image, video, file or audio message has no media_id, media_ids or media_url; or type is call, notification or deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The sender is not a member of the chat; an attached file is not in this chat, was not uploaded by the sender and is not in another chat they are in; an app login is not recognised, named another sender or was not added to this channel; a card was not sent by a bot with its own token; or, where the server enforces it, a person or bot named someone else as sender","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID, or no user with the sender's ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"chat_id is not a valid ID, or media_url was used (see that input)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.create"]}],"x-required-scopes":["chat.messages.create"]}},"/chat/{chat_id}/participant":{"post":{"tags":["Chats"],"summary":"Change a group's members","description":"Adds or removes a member of a group, or makes a member an admin or takes that away. Only a current admin who is still a member may do this. The group's members see the change live, and a removed person stops getting the group's messages at once. Removing someone also takes away their admin role; the last admin cannot be removed. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"manageParticipant","parameters":[{"name":"chat_id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the group. This route spells it chat_id; most Chat routes call the same ID chatId","example":"6ad1d0a1c2b3a4f5e6d7c801"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"operation":{"type":"string","enum":["add","remove","makeAdmin","removeAdmin"],"description":"What to do: add, remove, makeAdmin or removeAdmin","examples":["add"]},"requester_id":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]},"user_id":{"type":"string","description":"User ID of the person to add, remove, make admin or stop being admin","examples":["66f1b2c3d4e5f60718293a5c"]}},"required":["operation","requester_id","user_id"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"chat":{"type":"object","properties":{"_id":{"type":"string","description":"Chat ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"participants":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","description":"The person's user ID"},"name":{"type":"string","description":"Their name"},"email":{"type":"string","description":"Their email address"},"phone":{"type":"string","description":"Their phone number"},"organizationId":{"type":"string","description":"ID of their organisation"},"role":{"type":"string","description":"Their role in the organisation"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"},"onboarded":{"type":"boolean","description":"Whether they finished first-time setup"},"pbxExtension":{"type":"string","description":"Their extension on the office phone system, if any"},"profilePhoto":{"type":"string","description":"Address of their photo"},"commands":{"type":"array","description":"Slash commands a bot offers; empty for people"},"createdAt":{"type":"string","format":"date-time","description":"When they were added to Chat"},"updatedAt":{"type":"string","format":"date-time","description":"When their profile last changed"},"__v":{"type":"integer","description":"Internal revision counter"},"online":{"type":"boolean","description":"Whether they are connected to Chat now"},"lastSeen":{"type":"string","format":"date-time","description":"When they were last connected; absent when unknown"}}},"description":"The members after the change, each with their whole profile, photo address and online state"},"lastMessage":{"type":"object","properties":{"_id":{"type":"string"},"organizationId":{"type":"string"},"chat":{"type":"string"},"content":{"type":"string"},"type":{"type":"string"},"mentions":{"type":"array","items":{"type":"string"}},"reactions":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"userId":{"type":"string"},"emoji":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}},"medias":{"type":"array"},"edited":{"type":"boolean"},"isDeleted":{"type":"boolean"},"timestamp":{"type":"string","format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"__v":{"type":"integer"},"sender":{"type":"object","properties":{"_id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"phone":{"type":"string"},"organizationId":{"type":"string"},"role":{"type":"string"},"type":{"type":"string"},"onboarded":{"type":"boolean"},"pbxExtension":{"type":"string"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}}},"commands":{"type":"array"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"__v":{"type":"integer"}}},"viewedBy":{"type":"array","items":{"type":"string"}}},"description":"The newest message, with its sender's whole profile, its file and the message it replies to"},"chatName":{"type":"string","description":"The group's name, or the name given to a direct chat"},"profilePhoto":{"type":"string","description":"Address of the group's photo, or null"},"description":{"type":"string","description":"What the group is for"},"isGroupChat":{"type":"boolean","description":"true for a group or channel, false for a direct chat"},"groupAdmins":{"type":"array","items":{"type":"string"},"description":"IDs of the group's admins after the change"},"assistantAction":{"type":"string","description":"How bots answer here: assistant_tagged_reply (only when tagged or replied to), assistant_passive (read everything, reply when they can help) or assistant_free_reply (reply to everything)"},"chatType":{"type":"string","description":"chat, comment (a comment chat of a task or other item), external or notifications"},"seq":{"type":"integer","description":"Number of the chat's latest change; pass it as this chat's cursor to syncChanges"},"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"messageId":{"type":"string"},"pinnedBy":{"type":"string"},"pinnedAt":{"type":"string","format":"date-time"},"notifyMode":{"type":"string"}}},"description":"Pinned messages (messageId, pinnedBy, pinnedAt, notifyMode)"},"createdAt":{"type":"string","format":"date-time","description":"When the chat was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last had activity or changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"The group after the change"}}},"example":{"success":true,"chat":{"_id":"6ad1d0a1c2b3a4f5e6d7c801","organizationId":"66a4b275003d1b495212b5aa","participants":[{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","email":"amina@inet.africa","phone":"+254712345678","organizationId":"66a4b275003d1b495212b5aa","role":"Admin","type":"Human","onboarded":true,"pbxExtension":"2041","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","commands":[],"createdAt":"2026-08-20T07:00:00.000Z","updatedAt":"2026-10-16T08:55:00.000Z","__v":0,"online":true,"lastSeen":"2026-10-16T08:55:00.000Z"}],"lastMessage":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","content":"The October fibre invoice is in, please approve by Friday.","type":"text","mentions":["66f1b2c3d4e5f60718293a4b"],"reactions":[{"_id":"6ad1d0b2c3d4e5f6a7b8c9f1","userId":"66f1b2c3d4e5f60718293a4b","emoji":"👍","createdAt":"2026-10-16T09:12:00.000Z"}],"medias":[],"edited":false,"isDeleted":false,"timestamp":"2026-10-16T09:10:00.000Z","createdAt":"2026-10-16T09:10:00.000Z","updatedAt":"2026-10-16T09:12:00.000Z","__v":0,"sender":{"_id":"66f1b2c3d4e5f60718293a5c","name":"Brian Otieno","email":"brian@inet.africa","phone":"+254712345678","organizationId":"66a4b275003d1b495212b5aa","role":"Admin","type":"Human","onboarded":true,"pbxExtension":"2041","profilePhoto":{"minioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"commands":[],"createdAt":"2026-08-20T07:00:00.000Z","updatedAt":"2026-10-16T08:55:00.000Z","__v":0},"viewedBy":["66f1b2c3d4e5f60718293a4b"]},"chatName":"Finance team","profilePhoto":"https://blob.kazee.africa/org-66a4b275003d1b495212b5aa/chat/6ad1d0a1c2b3a4f5e6d7c801/finance-team-2026-10-12_10-15-00-thumb.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Expires=604800&X-Amz-Signature=3f9c2a1b5d7e4c1a","description":"Invoices, payments and month-end","isGroupChat":true,"groupAdmins":["66f1b2c3d4e5f60718293a4b"],"assistantAction":"assistant_tagged_reply","chatType":"chat","seq":42,"pinnedMessages":[{"_id":"6ad1d1c9d0e1f2a3b4c5d601","messageId":"6ad1d0b2c3d4e5f6a7b8c902","pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedAt":"2026-10-14T06:30:00.000Z","notifyMode":"notify"}],"createdAt":"2026-09-01T07:00:00.000Z","updatedAt":"2026-10-16T09:10:00.000Z","__v":3}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"requester_id is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: operation is not one of the four, no chat with that ID, it is a space or meeting room (change members in Spaces), another app manages it, you are not a current admin and member of a group, the person does not exist or is an app login (add), is already a member or admin, is not a member (remove or makeAdmin), is the last admin (remove), the group would have no admin left (removeAdmin), or an ID is not valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/user/{userId}/preferences":{"post":{"tags":["Settings"],"summary":"Change my settings for a chat","description":"Turns phone notifications for one chat on or off for you, and sets its background picture. Send only what you want to change. The background picture is not kept at present: whatever file you send, a placeholder picture link is saved instead. It does not look the chat up.\n\n**Permission:** `chat.users.update` (Update own profile).","operationId":"setUserPreference","parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","example":"66f1b2c3d4e5f60718293a4b"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"chatId":{"type":"string","description":"ID of the chat","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"notification":{"type":"boolean","description":"false to stop phone notifications from this chat, true to have them again. Must be a JSON true or false; the text \"true\" (as a form upload sends it) is refused","examples":[false]},"wallpaper":{"type":"string","format":"binary","description":"A picture for the chat's background, sent as multipart form data (see above: a placeholder is saved instead)"}},"required":["chatId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"Always \"Preference updated successfully\""},"preferences":{"type":"object","properties":{"chatId":{"type":"string","description":"The chat these settings are for"},"notification":{"type":"boolean","description":"Whether the chat sends you phone notifications; true unless you turned them off"},"wallpaper":{"description":"Link to the chat's background picture; null if none is set"}},"description":"Your settings for the chat after the change"}}},"example":{"success":true,"message":"Preference updated successfully","preferences":{"chatId":"6ad1d0a1c2b3a4f5e6d7c801","notification":false,"wallpaper":null}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"notification is not a JSON true or false, or wallpaper is not a file; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.update"]}],"x-required-scopes":["chat.users.update"]}},"/getAllMuteStatus":{"post":{"tags":["Settings"],"summary":"List all my mutes","description":"Gets all your mutes at once: the mute on all notifications and each chat you have muted, with when each ends.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getAllMuteStatus_2","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"globalMute":{"type":"object","properties":{"isGlobalMuted":{"type":"boolean","description":"Whether all your notifications are muted right now"},"muteUntil":{"description":"When the mute ends by itself; null when not muted"},"allowMentions":{"type":"boolean","description":"Whether @mentions of you still notify you while muted; true when not muted"}},"description":"Your mute on all notifications"},"mutedChats":{"type":"object","properties":{"6ad1d0a1c2b3a4f5e6d7c801":{"type":"object","properties":{"muteUntil":{"type":"string","format":"date-time","description":"When that chat's mute ends by itself"}},"description":"One muted chat (the key is its ID)"},"6ad1d0a1c2b3a4f5e6d7c802":{"type":"object","properties":{"muteUntil":{"type":"string","format":"date-time"}}}},"description":"The chats you have muted right now, keyed by chat ID; empty when none"}}},"example":{"success":true,"globalMute":{"isGlobalMuted":false,"muteUntil":null,"allowMentions":true},"mutedChats":{"6ad1d0a1c2b3a4f5e6d7c801":{"muteUntil":"2026-10-16T14:00:00.000Z"},"6ad1d0a1c2b3a4f5e6d7c802":{"muteUntil":"2026-10-23T06:00:00.000Z"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]}},"/getGlobalMuteStatus":{"post":{"tags":["Settings"],"summary":"Check whether all my notifications are muted","description":"Tells you whether you have muted all your notifications, until when, and whether @mentions still come through.\n\n**Permission:** `chat.users.read` (Read users).","operationId":"getGlobalMuteStatus_2","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"isGlobalMuted":{"type":"boolean","description":"Whether all your notifications are muted right now"},"muteUntil":{"type":"string","format":"date-time","description":"When the mute ends by itself; null when not muted"},"allowMentions":{"type":"boolean","description":"Whether @mentions of you still notify you while muted; true when not muted"}}},"example":{"success":true,"isGlobalMuted":true,"muteUntil":"2026-10-16T09:00:00.000Z","allowMentions":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.users.read"]}],"x-required-scopes":["chat.users.read"]}},"/setGlobalMute":{"post":{"tags":["Settings"],"summary":"Mute all my notifications","description":"Mutes every phone notification for you for a while, or ends the mute. While muted, @mentions of you still come through unless allowMentions is false. The mute ends by itself after duration; leaving duration out (or a JSON 0) ends it now. A new call replaces the previous mute.\n\n**Permission:** `chat.users.update` (Update own profile).","operationId":"setGlobalMute_2","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"allowMentions":{"type":"boolean","default":true,"description":"Whether @mentions of you still notify you while muted. Defaults to true. Must be a JSON true or false. Ending the mute sets it back to true","examples":[true]},"duration":{"type":"integer","minimum":0,"description":"How long to mute, in milliseconds, e.g. 3600000 for an hour. Leave it out, or send null or a JSON 0, to end the mute. Send a number: the text \"0\" mutes with no end","examples":[3600000]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"Global mute enabled, or Global mute disabled"},"isGlobalMuted":{"type":"boolean","description":"Whether all your notifications are muted right now"},"muteUntil":{"type":"string","format":"date-time","description":"When the mute ends by itself; null when not muted"},"allowMentions":{"type":"boolean","description":"Whether @mentions of you still notify you while muted; true when not muted"}}},"example":{"success":true,"message":"Global mute enabled","isGlobalMuted":true,"muteUntil":"2026-10-16T09:00:00.000Z","allowMentions":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"duration is not a number of milliseconds of 0 or more, or allowMentions is not a JSON true or false; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.users.update"]}],"x-required-scopes":["chat.users.update"]}},"/muteChat":{"post":{"tags":["Settings"],"summary":"Mute a chat","description":"Stops phone notifications from one chat for you for a while, or unmutes it. The mute ends by itself after duration; leaving duration out (or a JSON 0) unmutes now. A new call replaces the previous mute. It does not look the chat up or check you are in it.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"muteChat_2","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chatId":{"type":"string","description":"ID of the chat","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"duration":{"type":"integer","minimum":0,"description":"How long to mute, in milliseconds, e.g. 28800000 for 8 hours. Leave it out, or send null or a JSON 0, to unmute. Send a number: the text \"0\" mutes the chat with no end","examples":[28800000]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["chatId","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"Chat muted successfully, or Chat unmuted successfully"},"chatId":{"type":"string","description":"The chat"},"muteUntil":{"type":"string","format":"date-time","description":"When the mute ends by itself; null after unmuting"},"isMuted":{"type":"boolean","description":"Whether the chat is muted now"}}},"example":{"success":true,"message":"Chat muted successfully","chatId":"6ad1d0a1c2b3a4f5e6d7c801","muteUntil":"2026-10-16T14:00:00.000Z","isMuted":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"duration is not a number of milliseconds of 0 or more; the answer is { success: false, error }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/getChatMuteStatus":{"post":{"tags":["Settings"],"summary":"Check whether I muted a chat","description":"Tells you whether you have muted one chat and until when. It does not look the chat up, so an unknown chat ID answers not muted.\n\n**Permission:** `chat.chats.read` (Read chats).","operationId":"getChatMuteStatus_2","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chatId":{"type":"string","description":"ID of the chat","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in)","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["chatId","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"chatId":{"type":"string","description":"The chat"},"isMuted":{"type":"boolean","description":"Whether you have muted it right now"},"muteUntil":{"type":"string","format":"date-time","description":"When the mute ends by itself; null when not muted"}}},"example":{"success":true,"chatId":"6ad1d0a1c2b3a4f5e6d7c801","isMuted":true,"muteUntil":"2026-10-16T14:00:00.000Z"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or you are calling with an app or service token rather than as a person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.read"]}],"x-required-scopes":["chat.chats.read"]}},"/migrate/media":{"post":{"tags":["Media & files"],"summary":"Link old files to their chats","description":"A one-off repair for the whole organisation: goes through every chat and records, on each file sent in its messages, which chat it belongs to, so older files show in the chat's file list. Run it first with dryRun true to see the counts without changing anything. It can take a long time on a large organisation.\n\n**Permission:** `chat.media.admin` (Migrate media).","operationId":"migrateMedia","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"dryRun":{"type":"boolean","default":false,"description":"true counts what would change without changing anything. Must be a JSON true or false; text such as \"true\" is refused","examples":[true]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"true when the run finished (a chat that failed is listed in stats.errors, not a failure)"},"message":{"type":"string","description":"Whether it was a dry run"},"stats":{"type":"object","properties":{"totalChats":{"type":"integer","description":"Chats looked at: every chat in the organisation"},"totalMessages":{"type":"integer","description":"Messages with files found in them"},"totalMediaUpdated":{"type":"integer","description":"Files given their chat (or that would be, on a dry run)"},"totalMediaSkipped":{"type":"integer","description":"Files that already had the right chat"},"totalMediaErrors":{"type":"integer","description":"Always 0"},"errors":{"type":"array","items":{"type":"string"},"description":"One line for each chat that could not be processed"}},"description":"What the run found"}}},"example":{"success":true,"message":"Dry run completed. No changes were made.","stats":{"totalChats":412,"totalMessages":3180,"totalMediaUpdated":96,"totalMediaSkipped":3121,"totalMediaErrors":0,"errors":["Error processing chat 6ad1d0a1c2b3a4f5e6d7c802: Cast to ObjectId failed"]}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"dryRun is not true or false, or the run stopped part way (stats then shows how far it got)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.media.admin"]}],"x-required-scopes":["chat.media.admin"]}},"/chatGroup":{"post":{"tags":["Chat folders"],"summary":"Create a chat folder","description":"Creates one of your own folders for sorting your chat list. Names are trimmed and must differ from your other folders' names. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.groups.create` (Create chat folders).","operationId":"createChatGroup","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"color":{"type":"string","default":"#6366f1","description":"Its colour as a hex code","examples":["#6366f1"]},"icon":{"type":"string","description":"An icon name, e.g. briefcase, home or star","examples":["briefcase"]},"name":{"type":"string","maxLength":50,"description":"The folder's name, up to 50 characters","examples":["Work"]},"order":{"type":"integer","default":0,"description":"Its position among your folders; lower comes first","examples":[0]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["name","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"group":{"type":"object","properties":{"_id":{"type":"string","description":"Folder ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"userId":{"type":"string","description":"ID of the person who owns the folder"},"name":{"type":"string","description":"Its name, up to 50 characters, unique among your folders"},"color":{"type":"string","description":"Its colour as a hex code"},"icon":{"type":"string","description":"Its icon name, if any, e.g. briefcase"},"order":{"type":"integer","description":"Its position among your folders; lower comes first"},"pinnedChats":{"type":"array","description":"IDs of the chats pinned at the top of this folder"},"createdAt":{"type":"string","format":"date-time","description":"When it was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"The new folder"}}},"example":{"success":true,"group":{"_id":"6ad1d1a7b8c9d0e1f2a3b401","organizationId":"66a4b275003d1b495212b5aa","userId":"66f1b2c3d4e5f60718293a4b","name":"Work","color":"#6366f1","icon":"briefcase","order":0,"pinnedChats":[],"createdAt":"2026-10-01T07:00:00.000Z","updatedAt":"2026-10-01T07:00:00.000Z","__v":0}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: you already have a folder with that name, or the name is over 50 characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.groups.create"]}],"x-required-scopes":["chat.groups.create"]}},"/chatGroup/assign":{"post":{"tags":["Chat folders"],"summary":"Put a chat in a folder","description":"Puts a chat in one of your folders, moving it out of any other, or takes it out of folders when groupId is left out or null. A chat is in at most one of your folders. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.groups.update` (Update chat folders).","operationId":"assignChatToGroup","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chatId":{"type":"string","description":"ID of the chat","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"groupId":{"type":"string","description":"ID of your folder to put it in; leave out or send null to take the chat out of folders","examples":["6ad1d1a7b8c9d0e1f2a3b401"]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["chatId","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"settings":{"type":"object","properties":{"_id":{"type":"string","description":"ID of this settings record"},"userId":{"type":"string","description":"Your user ID"},"chatId":{"type":"string","description":"Chat ID"},"groupId":{"type":"string","description":"ID of the folder the chat is in, or null for none"},"organizationId":{"type":"string","description":"ID of the organisation"},"markedUnread":{"type":"boolean","description":"Whether you marked the chat as unread"},"lastReadAt":{"type":"string","format":"date-time","description":"Every message up to this time is read by you, or null"},"pinned":{"type":"boolean","description":"Whether you pinned the chat to the top of your list"},"pinnedAt":{"type":"string","format":"date-time","description":"When you pinned it, or null"},"archived":{"type":"boolean","description":"Whether you archived it"},"archivedAt":{"description":"When you archived it, or null"},"archiveVersion":{"type":"integer","description":"How many times you archived or restored it"},"threadActivityAt":{"description":"When a thread you follow there last had a reply, or null"},"createdAt":{"type":"string","format":"date-time","description":"When this record was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"Your personal settings for the chat after the change"}}},"example":{"success":true,"settings":{"_id":"6ad1d1b8c9d0e1f2a3b4c501","userId":"66f1b2c3d4e5f60718293a4b","chatId":"6ad1d0a1c2b3a4f5e6d7c801","groupId":"6ad1d1a7b8c9d0e1f2a3b401","organizationId":"66a4b275003d1b495212b5aa","markedUnread":false,"lastReadAt":"2026-10-16T09:10:00.000Z","pinned":true,"pinnedAt":"2026-10-02T08:00:00.000Z","archived":false,"archivedAt":null,"archiveVersion":0,"threadActivityAt":null,"createdAt":"2026-09-01T07:05:00.000Z","updatedAt":"2026-10-16T09:31:00.000Z","__v":0}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: no folder of yours with that groupId, or an ID is not valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.groups.update"]}],"x-required-scopes":["chat.groups.update"]}},"/chatGroup/pin":{"post":{"tags":["Chat folders"],"summary":"Pin a chat in a folder","description":"Pins a chat at the top of one of your folders, or unpins it. Pinning a chat already pinned there changes nothing. To pin a chat at the top of your whole chat list, use setChatPinned. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.groups.update` (Update chat folders).","operationId":"toggleChatPin","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chatId":{"type":"string","description":"ID of the chat","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"groupId":{"type":"string","description":"ID of your folder","examples":["6ad1d1a7b8c9d0e1f2a3b401"]},"pinned":{"type":"boolean","description":"true to pin, false to unpin. Send a JSON true or false: any text, even \"false\", pins","examples":[true]},"userId":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["chatId","groupId","pinned","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"pinned":{"type":"boolean","description":"The pinned value you sent"},"group":{"type":"object","properties":{"_id":{"type":"string","description":"Folder ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"userId":{"type":"string","description":"ID of the person who owns the folder"},"name":{"type":"string","description":"Its name, up to 50 characters, unique among your folders"},"color":{"type":"string","description":"Its colour as a hex code"},"icon":{"type":"string","description":"Its icon name, if any, e.g. briefcase"},"order":{"type":"integer","description":"Its position among your folders; lower comes first"},"pinnedChats":{"type":"array","items":{"type":"string"},"description":"IDs of the chats pinned at the top of this folder"},"createdAt":{"type":"string","format":"date-time","description":"When it was created"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal revision counter"}},"description":"The folder after the change"}}},"example":{"success":true,"pinned":true,"group":{"_id":"6ad1d1a7b8c9d0e1f2a3b401","organizationId":"66a4b275003d1b495212b5aa","userId":"66f1b2c3d4e5f60718293a4b","name":"Work","color":"#6366f1","icon":"briefcase","order":0,"pinnedChats":["6ad1d0a1c2b3a4f5e6d7c801"],"createdAt":"2026-10-01T07:00:00.000Z","updatedAt":"2026-10-16T09:00:00.000Z","__v":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"userId is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: no folder of yours with that groupId, or an ID is not valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.groups.update"]}],"x-required-scopes":["chat.groups.update"]}},"/notifications/{notificationId}/read":{"post":{"tags":["Notifications"],"summary":"Mark a notification as read","description":"Marks one of your notifications as read. Marking it again moves its read time on.\n\n**Permission:** `chat.notifications.update` (Mark notifications).","operationId":"notifications_mark_read","parameters":[{"name":"notificationId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the notification","example":"6ad1d1b8c9daebfc0d1e2f01"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"notification":{"type":"object","properties":{"_id":{"type":"string","description":"Notification ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"user":{"type":"string","description":"ID of the person it is for"},"category":{"type":"string","description":"Free-text kind the sender gave, e.g. task, story, reaction"},"notificationType":{"type":"string","description":"mention, reply, reaction, comment_added, system, marketing or pin"},"source":{"type":"string","description":"Which app and kind of item it came from, e.g. spaces:task; absent for older notifications"},"sourceEntityId":{"type":"string","description":"ID of that item, for opening it"},"actorId":{"type":"string","description":"ID of the person who caused it"},"content":{"type":"string","description":"The notification text"},"title":{"type":"string","description":"The notification heading"},"data":{"type":"object","properties":{"entityType":{"type":"string"},"entityTitle":{"type":"string"}},"description":"Extra details the sending app attached, for opening the right screen"},"success":{"type":"boolean","description":"Whether the push worked, or true when there was no phone to push to"},"isRead":{"type":"boolean","description":"Whether it has been marked read"},"createdAt":{"type":"string","format":"date-time","description":"When it was made"},"__v":{"type":"integer","description":"Internal version counter"},"readAt":{"type":"string","format":"date-time","description":"When it was marked read"}},"description":"The notification after the change"}}},"example":{"notification":{"_id":"6ad1d1b8c9daebfc0d1e2f01","organizationId":"66a4b275003d1b495212b5aa","user":"66f1b2c3d4e5f60718293a4b","category":"task","notificationType":"mention","source":"spaces:task","sourceEntityId":"6ad1d1e1f2a3b4c5d6e7f801","actorId":"66f1b2c3d4e5f60718293a5c","content":"@Amina Wanjiru can you send this today?","title":"Brian Otieno mentioned you on Send the October invoice","data":{"entityType":"task","entityTitle":"Send the October invoice"},"success":true,"isRead":true,"createdAt":"2026-10-16T06:40:00.000Z","__v":0,"readAt":"2026-10-16T07:05:00.000Z"}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No notification of yours with that ID; the answer is { error, status }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"notificationId is not a valid ID; the answer is { error, status }","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.notifications.update"]}],"x-required-scopes":["chat.notifications.update"]}},"/notifications/mark-all-read":{"post":{"tags":["Notifications"],"summary":"Mark all my notifications as read","description":"Marks all your unread notifications as read, or only those from one app or item kind.\n\n**Permission:** `chat.notifications.update` (Mark notifications).","operationId":"notifications_mark_all_read","requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","description":"Only notifications from this source. With a colon it must match exactly (spaces:task); without, it matches every source that starts with it and a colon (spaces matches spaces:task and spaces:event)","examples":["spaces:task"]}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"modifiedCount":{"type":"integer","description":"How many unread notifications were marked read"}}},"example":{"modifiedCount":3}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.notifications.update"]}],"x-required-scopes":["chat.notifications.update"]}},"/notifications/send":{"post":{"tags":["Notifications"],"summary":"Send a notification to a person","description":"Saves a notification with your title and text in the notification list of one person in your organisation and tries to push it to their phone. For administrators. As the code stands it only works for people with no phone registered: for others the push step fails and nothing is saved.\n\n**Permission:** `chat.notifications.admin` (Bulk-mark notifications).","operationId":"notifications_action_user","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","description":"Free-text kind of notification, e.g. reminder","examples":["reminder"]},"content":{"type":"string","description":"The notification text","examples":["Please send me the October invoice before noon."]},"title":{"type":"string","description":"The notification heading","examples":["Invoice reminder"]},"userId":{"type":"string","description":"ID of the person to notify","examples":["66f1b2c3d4e5f60718293a5c"]}},"required":["category","content","title","userId"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"notifications":{"type":"array","items":{"type":"object","properties":{"message":{"type":"string","description":"Notification Sent: true, or false if the push failed"},"data":{"type":"object","properties":{"_id":{"type":"string","description":"Notification ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"user":{"type":"string","description":"ID of the person it is for"},"category":{"type":"string","description":"Free-text kind the sender gave, e.g. task, story, reaction"},"notificationType":{"type":"string","description":"mention, reply, reaction, comment_added, system, marketing or pin"},"content":{"type":"string","description":"The notification text"},"title":{"type":"string","description":"The notification heading"},"success":{"type":"boolean","description":"Whether the push worked, or true when there was no phone to push to"},"isRead":{"type":"boolean","description":"Whether it has been marked read"},"createdAt":{"type":"string","format":"date-time","description":"When it was made"},"__v":{"type":"integer","description":"Internal version counter"}},"description":"The notification as saved"}}},"description":"The one notification made"}}},"example":{"notifications":[{"message":"Notification Sent: true","data":{"_id":"6ad1d1b8c9daebfc0d1e2f01","organizationId":"66a4b275003d1b495212b5aa","user":"66f1b2c3d4e5f60718293a5c","category":"reminder","notificationType":"system","content":"Please send me the October invoice before noon.","title":"Invoice reminder","success":true,"isRead":false,"createdAt":"2026-10-16T07:00:00.000Z","__v":0}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No person with that ID in your organisation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"A phone is registered for the person, and the push step fails, so nothing is saved (the answer has no error text)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.notifications.admin"]}],"x-required-scopes":["chat.notifications.admin"]}},"/notifications/bulk":{"post":{"tags":["Notifications"],"summary":"Send a notification to everyone","description":"Meant to send one notification to everyone with a phone registered. It picks people whose stored record lists phone tokens, which Chat's records do not keep, so it normally finds nobody and answers 0 succeeded, 0 failed; only people in your organisation. For administrators.\n\n**Permission:** `chat.notifications.admin` (Bulk-mark notifications).","operationId":"notifications_action_bulk","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"category":{"type":"string","description":"Free-text kind of notification, e.g. outage or reminder","examples":["reminder"]},"content":{"type":"string","description":"The notification text","examples":["The office is closed on Monday 20 October for the public holiday."]},"title":{"type":"string","description":"The notification heading","examples":["Office closed on Monday"]}},"required":["category","content","title"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","description":"Bulk notifications sent: N succeeded, M failed"},"status":{"type":"integer","description":"Always 200"},"successCount":{"type":"integer","description":"How many people it was saved for"},"failedCount":{"type":"integer","description":"How many it failed for"}}},"example":{"message":"Bulk notifications sent: 0 succeeded, 0 failed","status":200,"successCount":0,"failedCount":0}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.notifications.admin"]}],"x-required-scopes":["chat.notifications.admin"]}},"/stories":{"post":{"tags":["Stories"],"summary":"Post a story","description":"Posts a picture or video as your story, sent as multipart form data; it disappears 24 hours later. Everyone who shares a chat with you sees it appear live, and each person tagged in mentions gets a phone notification. A video gets a still of its first frame when one can be made.\n\n**Permission:** `chat.stories.create` (Post stories).","operationId":"createStory","requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"caption":{"type":"string","maxLength":200,"description":"Text shown with it, up to 200 characters","examples":["Sunrise over Ngong Hills"]},"media":{"type":"string","format":"binary","description":"The picture or video, at most 200 MB. A file whose type cannot be told is treated as a picture"},"mentions":{"type":"string","description":"People to tag, as a JSON list in text: [{\"userId\": \"...\", \"userName\": \"...\"}]. Text that is not such a list is ignored","examples":["[{\"userId\":\"66f1b2c3d4e5f60718293a4b\",\"userName\":\"Amina Wanjiru\"}]"]},"userId":{"type":"string","description":"Ignored: the story is always yours. Older apps still send it","examples":["66f1b2c3d4e5f60718293a4b"],"deprecated":true}},"required":["media"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"story":{"type":"object","properties":{"_id":{"type":"string","description":"Story ID"},"userId":{"type":"string","description":"ID of the person who posted it (you)"},"mediaUrl":{"type":"string","description":"Link to the picture or video, valid 7 days without sign-in"},"mediaType":{"type":"string","description":"image or video"},"posterUrl":{"description":"For a video, link to a still of its first frame; null for a picture or if none could be made"},"caption":{"type":"string","description":"The caption; absent if none"},"mentions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of a tagged person"},"userName":{"type":"string","description":"Their name, as sent"}}},"description":"People tagged in it, as sent; absent if none"},"createdAt":{"type":"string","format":"date-time","description":"When it was posted"},"expiresAt":{"type":"string","format":"date-time","description":"When it disappears: 24 hours after posting"},"viewerCount":{"type":"integer","description":"How many people have seen it"}},"description":"The new story"}}},"example":{"success":true,"story":{"_id":"6ad1d0e5f6a7b8c9daebf201","userId":"66f1b2c3d4e5f60718293a5c","mediaUrl":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/stories/66f1b2c3d4e5f60718293a5c/sunrise-2026-10-16_06-05-12.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","mediaType":"image","posterUrl":null,"caption":"Sunrise over Ngong Hills","mentions":[{"userId":"66f1b2c3d4e5f60718293a4b","userName":"Amina Wanjiru"}],"createdAt":"2026-10-16T06:05:12.000Z","expiresAt":"2026-10-17T06:05:12.000Z","viewerCount":0}}}}},"400":{"description":"caption is over 200 characters, no file was sent, or the file is not a picture or video","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"The file could not be stored","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.create"]}],"x-required-scopes":["chat.stories.create"]}},"/stories/{storyId}/view":{"post":{"tags":["Stories"],"summary":"Mark a story as seen","description":"Records that you have seen a story. The first time, its owner (and your other devices) are told live. Seeing it again, or seeing your own story, records nothing. Only for a story you can see: your own, or one by someone you share a chat with.\n\n**Permission:** `chat.stories.read` (View stories).","operationId":"viewStory","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf201"}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","description":"Ignored: you are always the viewer. Older apps still send it","examples":["66f1b2c3d4e5f60718293a4b"],"deprecated":true}}}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"success":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No story with that ID, or it has disappeared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.read"]}],"x-required-scopes":["chat.stories.read"]}},"/stories/batch-view":{"post":{"tags":["Stories"],"summary":"Mark several stories as seen","description":"Records that you have seen up to 50 stories at once. Stories you already saw, your own, unknown, expired or not visible to you (by someone you share no chat with) are skipped. When at least one is new, the owner of each story you have now seen is told live.\n\n**Permission:** `chat.stories.read` (View stories).","operationId":"batchViewStories","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"storyIds":{"type":"array","items":{"type":"string"},"description":"IDs of the stories, 1 to 50 (a JSON list in text also works). Entries that are not text are dropped","examples":[["6ad1d0e5f6a7b8c9daebf201","6ad1d0e5f6a7b8c9daebf202"]]}},"required":["storyIds"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"recorded":{"type":"integer","description":"How many stories you had not seen before this call"}}},"example":{"success":true,"recorded":2}}}},"400":{"description":"storyIds holds no IDs, or more than 50","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"One of storyIds is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.read"]}],"x-required-scopes":["chat.stories.read"]}},"/stories/{storyId}/react":{"post":{"tags":["Stories"],"summary":"React to a story","description":"Adds an emoji reaction to a story, or takes it off if you already left that same emoji; you may leave several different ones. A new reaction is shown live to everyone who can see the story (taking one off is not), and the story's owner gets a phone notification unless it is their own story. Only for a story you can see: your own, or one by someone you share a chat with.\n\n**Permission:** `chat.stories.update` (React to stories).","operationId":"reactStory","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf202"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"emoji":{"type":"string","maxLength":16,"description":"The emoji; at most 16 characters, where most emoji count as 2","examples":["😍"]},"userId":{"type":"string","description":"Ignored: you are always the one reacting. Older apps still send it","examples":["66f1b2c3d4e5f60718293a4b"],"deprecated":true}},"required":["emoji"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"action":{"type":"string","description":"added if your reaction was added, removed if the same emoji from you was taken off"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of the person who reacted"},"userName":{"type":"string","description":"Their name when they reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"},"_id":{"type":"string","description":"ID of the reaction"}}},"description":"All reactions on the story after the change, oldest first"}}},"example":{"success":true,"action":"added","reactions":[{"userId":"66f1b2c3d4e5f60718293a4b","userName":"Amina Wanjiru","emoji":"😍","createdAt":"2026-10-16T06:20:00.000Z","_id":"6ad1d1c9daebfc0d1e2f3a01"}]}}}},"400":{"description":"emoji is empty or over 16 characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No story with that ID, or it has disappeared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"The story has expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.update"]}],"x-required-scopes":["chat.stories.update"]}},"/stories/{storyId}/reply":{"post":{"tags":["Stories"],"summary":"Reply to a story","description":"Replies privately to the story of someone you share a chat with: sends your text as a message in your direct chat with its owner, starting that chat if you have none, with a reference to the story. The chat sees the message live, and the owner also gets a story reply event and a phone notification.\n\n**Permission:** `chat.messages.create` (Send messages).","operationId":"replyStory","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf202"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"content":{"type":"string","description":"Your reply","examples":["Lovely view! Where is this?"]},"userId":{"type":"string","description":"Ignored: you are always the sender. Older apps still send it","examples":["66f1b2c3d4e5f60718293a4b"],"deprecated":true}},"required":["content"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"chatId":{"type":"string","description":"ID of your direct chat with the story's owner"},"message":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation"},"chat":{"type":"string","description":"ID of the direct chat it was sent in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Your user ID"},"name":{"type":"string","description":"Your name"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}},"description":"Where your profile photo is stored"},"type":{"type":"string","description":"Human for a person, AI for a bot"}},"description":"You: _id, name, type and where your profile photo is stored (not a link)"},"content":{"type":"string","description":"Your reply"},"type":{"type":"string","description":"Always story_reply"},"storyRef":{"type":"object","properties":{"storyId":{"type":"string","description":"Its ID"},"mediaUrl":{"type":"string","description":"Link to its picture or video, valid 7 days"},"mediaType":{"type":"string","description":"image or video"},"caption":{"type":"string","description":"Its caption; absent if none"}},"description":"The story you replied to, as it was then"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"Buttons on the message; always empty here"},"medias":{"type":"array","description":"Files on the message; always empty here"},"viewedBy":{"type":"array","description":"IDs of people who have seen the message; empty when new"},"mentions":{"type":"array","description":"IDs of people mentioned; always empty here"},"reactions":{"type":"array","description":"Reactions on the message; empty when new"},"editHistory":{"type":"array","description":"Earlier versions after edits; empty when new"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"Poll settings every message carries; unused here"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Notification details every message carries; unused here"},"edited":{"type":"boolean","description":"Whether it has been edited"},"isDeleted":{"type":"boolean","description":"Whether it has been deleted"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was sent"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed"},"__v":{"type":"integer","description":"Internal version counter"}},"description":"The reply as a message in that chat"}}},"example":{"success":true,"chatId":"6ad1d0a1c2b3a4f5e6d7c801","message":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":{"minioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profile-photos/66f1b2c3d4e5f60718293a4b/amina-2026-10-02_09-14-05-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"type":"Human"},"content":"Lovely view! Where is this?","type":"story_reply","storyRef":{"storyId":"6ad1d0e5f6a7b8c9daebf202","mediaUrl":"https://blobstore.inet.africa/org-66a4b275003d1b495212b5aa/chat/stories/66f1b2c3d4e5f60718293a5c/sunrise-2026-10-16_06-05-12.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=chat%2F20261016%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20261016T061500Z&X-Amz-Expires=604800&X-Amz-SignedHeaders=host&X-Amz-Signature=9c1e7b2f4a6d","mediaType":"image","caption":"Sunrise over Ngong Hills"},"interactive":{"buttons":[]},"medias":[],"viewedBy":[],"mentions":[],"reactions":[],"editHistory":[],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":false,"isDeleted":false,"timestamp":"2026-10-16T06:45:00.000Z","createdAt":"2026-10-16T06:45:00.000Z","updatedAt":"2026-10-16T06:45:00.000Z","__v":0}}}}},"400":{"description":"The story is your own","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"No story with that ID, or it has disappeared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"The story has expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.create"]}],"x-required-scopes":["chat.messages.create"]}},"/stories/{storyId}/comments/{commentId}/react":{"post":{"tags":["Stories"],"summary":"React to a story comment","description":"Reacts to a story comment or reply with an emoji. You keep one reaction per comment: a different emoji replaces yours, the same one takes it off. The comment's author and the story's owner see the change live, and a new reaction from someone else is sent to the comment's author in their notifications chat. Open to the story's owner and anyone who shares a chat with them.\n\n**Permission:** `chat.comments.update` (React to comments).","operationId":"reactStoryComment","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf202"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the comment or reply","example":"6ad1d1a7b8c9daebfc0d1e01"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"emoji":{"type":"string","maxLength":16,"description":"The emoji; at most 16 characters, where most emoji count as 2","examples":["👍"]}},"required":["emoji"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"action":{"type":"string","description":"added, updated (your earlier emoji was swapped for this one) or removed (you sent the same emoji again)"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"ID of the person who reacted"},"userName":{"type":"string","description":"Their name when they reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"}}},"description":"All reactions on the comment after the change"}}},"example":{"success":true,"action":"added","reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","userName":"Brian Otieno","emoji":"👍","createdAt":"2026-10-16T06:20:00.000Z"}]}}}},"400":{"description":"emoji is empty or over 16 characters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You do not share a chat with the story's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No story with that ID (or it has disappeared), or no such comment on it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"410":{"description":"The comment was deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId or commentId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.comments.update"]}],"x-required-scopes":["chat.comments.update"]}},"/getPinnedMessages":{"post":{"tags":["Messages"],"summary":"List a chat's pinned messages","description":"Lists the pinned messages of a chat you are in, each with the whole message and who pinned it. Pins whose message no longer exists are dropped from the chat as they are found.\n\n**Permission:** `chat.messages.read` (Read messages).","operationId":"getPinnedMessages","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chat_id":{"type":"string","description":"ID of the chat","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"user_id":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["chat_id","user_id"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the pinned message"},"pinnedBy":{"type":"string","description":"ID of the member it was pinned as"},"pinnedByName":{"type":"string","description":"Their name, or Unknown"},"pinnedAt":{"type":"string","format":"date-time","description":"When it was pinned"},"message":{"type":"object","properties":{"_id":{"type":"string","description":"Message ID"},"organizationId":{"type":"string","description":"ID of the organisation it belongs to"},"chat":{"type":"string","description":"ID of the chat it is in"},"sender":{"type":"object","properties":{"_id":{"type":"string","description":"Their user ID"},"name":{"type":"string","description":"Their name"},"profilePhoto":{"type":"object","properties":{"minioPath":{"type":"string"},"bucketName":{"type":"string"},"thumbMinioPath":{"type":"string"},"thumbBucketName":{"type":"string"}},"description":"An object, not a link: where their photo is stored (minioPath and bucketName, and the small copy's thumbMinioPath and thumbBucketName); absent when they have none. Calls that read messages (List a chat's messages, Read a thread) give a signed link string instead"},"type":{"type":"string","description":"Human for a person, AI for a bot, App for an outside system's app login"}},"description":"Who sent it"},"content":{"type":"string","description":"The text, or the caption of a photo, video or file. A mention is written @[Name](userId). Empty once deleted"},"status":{"type":"string","description":"delivered once saved"},"type":{"type":"string","description":"text, image, video, file, audio, location, interactive, poll, call, story_reply, system (Chat's own notices, such as a pin), notification or deleted"},"interactive":{"type":"object","properties":{"buttons":{"type":"array"}},"description":"An interactive message's buttons (id, label, style, payload) and, once someone pressed one, selectedButtonId, selectedBy and selectedAt; buttons is empty on other messages"},"medias":{"type":"array","items":{"type":"string"},"description":"IDs of the files attached to it (not the files themselves)"},"viewedBy":{"type":"array","items":{"type":"string"},"description":"IDs of the people who have read it"},"mentions":{"type":"array","items":{"type":"string"},"description":"IDs of the people it mentions (everyone in the chat for @all)"},"pollData":{"type":"object","properties":{"allowMultipleVotes":{"type":"boolean"},"anonymous":{"type":"boolean"},"closed":{"type":"boolean"},"options":{"type":"array"}},"description":"A poll message's question and options (each with its text and voters), and its allowMultipleVotes, anonymous and closed settings; options is empty on other messages"},"notificationData":{"type":"object","properties":{"actors":{"type":"array"}},"description":"Details of an entry in a person's notifications chat; actors is empty on other messages"},"edited":{"type":"boolean","description":"Whether its text was changed after sending"},"isDeleted":{"type":"boolean","description":"Whether it was deleted; a deleted message keeps its place with type deleted and nothing in it"},"reactions":{"type":"array","items":{"type":"object","properties":{"userId":{"type":"string","description":"Who reacted"},"emoji":{"type":"string","description":"The emoji"},"createdAt":{"type":"string","format":"date-time","description":"When they reacted"},"_id":{"type":"string","description":"ID of the reaction"}}},"description":"Emoji reactions to it"},"timestamp":{"type":"string","format":"date-time","description":"When it was sent"},"createdAt":{"type":"string","format":"date-time","description":"When it was saved"},"updatedAt":{"type":"string","format":"date-time","description":"When it last changed in any way, including someone reading it"},"__v":{"type":"integer","description":"Revision number the database keeps; ignore it"},"editedAt":{"type":"string","format":"date-time","description":"When its text was last changed"},"editHistory":{"type":"array","items":{"type":"object","properties":{"content":{"type":"string","description":"The text before that edit"},"editedAt":{"type":"string","format":"date-time","description":"When it was replaced"},"_id":{"type":"string","description":"ID of the entry"}}},"description":"Earlier versions of its text"}},"description":"The whole message as stored. Keys only some messages carry appear only when set: replyTo (the quoted message, filled in with its sender and files), replyToMediaId, replyToChat and replyToChatName, threadRoot and alsoInChannel (a thread reply), threadReplyCount, threadLastReplyAt, threadParticipants, threadTitle, threadTitleBy, threadTitleAt and threadStart (a thread's root), location, linkPreview, card (a bot's Kazee Card with its public state, plus your own answer as card.mine), forwardedFrom, storyRef, systemData, editedAt, deletedAt and findMeCode. A card comes back whole here, including totals and who decided that the card's settings may hide elsewhere"}}},"description":"The chat's pins, most recently pinned first; empty when there are none"}}},"example":{"pinnedMessages":[{"messageId":"6ad1d0b2c3d4e5f6a7b8c901","pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedByName":"Amina Wanjiru","pinnedAt":"2026-10-16T05:20:31.000Z","message":{"_id":"6ad1d0b2c3d4e5f6a7b8c901","organizationId":"66a4b275003d1b495212b5aa","chat":"6ad1d0a1c2b3a4f5e6d7c801","sender":{"_id":"66f1b2c3d4e5f60718293a4b","name":"Amina Wanjiru","profilePhoto":{"minioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00.jpg","bucketName":"org-66a4b275003d1b495212b5aa","thumbMinioPath":"chat/profiles/66f1b2c3d4e5f60718293a4b/amina-2026-09-01_08-00-00-thumb.jpg","thumbBucketName":"org-66a4b275003d1b495212b5aa"},"type":"Human"},"content":"Signed delivery note for the October invoice. @[Brian Otieno](66f1b2c3d4e5f60718293a5c) can you file it today?","status":"delivered","type":"image","interactive":{"buttons":[]},"medias":["6ad1d0d4e5f6a7b8c9dae101"],"viewedBy":["66f1b2c3d4e5f60718293a5c"],"mentions":["66f1b2c3d4e5f60718293a5c"],"pollData":{"allowMultipleVotes":false,"anonymous":false,"closed":false,"options":[]},"notificationData":{"actors":[]},"edited":true,"isDeleted":false,"reactions":[{"userId":"66f1b2c3d4e5f60718293a5c","emoji":"👍","createdAt":"2026-10-16T05:14:40.000Z","_id":"6ad1d0f7b8c9daebfc0d1e01"}],"timestamp":"2026-10-16T05:12:03.000Z","createdAt":"2026-10-16T05:12:03.000Z","updatedAt":"2026-10-16T05:14:40.000Z","__v":0,"editedAt":"2026-10-16T05:13:20.000Z","editHistory":[{"content":"Signed delivery note for the October invoice.","editedAt":"2026-10-16T05:13:20.000Z","_id":"6ad1d1f8c9daebfc0d1e2f02"}]}}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"user_id is not the signed-in person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No chat with that ID, you are not a member of it, or chat_id is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.read"]}],"x-required-scopes":["chat.messages.read"]}},"/pinMessage":{"post":{"tags":["Messages"],"summary":"Pin a message","description":"Pins a message to the top of a chat; a chat holds at most 100 pins. Unless notify is false, a notice \"<name> pinned a message\" is posted in the chat from you and the other members get a push notification. Everyone in the chat sees the pin live.\n\n**Permission:** `chat.messages.update` (Edit messages).","operationId":"pinMessage","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chat_id":{"type":"string","description":"ID of the chat","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"message_id":{"type":"string","description":"ID of the message to pin; it must be in this chat","examples":["6ad1d0b2c3d4e5f6a7b8c901"]},"notify":{"type":"boolean","default":true,"description":"false (a JSON false; the text \"false\" counts as true) to pin quietly: no notice in the chat and no push","examples":[true]},"user_id":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["chat_id","message_id","user_id"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the pinned message"},"pinnedBy":{"type":"string","description":"ID of the member it was pinned as"},"pinnedAt":{"type":"string","format":"date-time","description":"When it was pinned"},"notifyMode":{"type":"string","description":"notify when the chat was told about the pin, silent when it was pinned quietly"},"_id":{"type":"string","description":"ID of the pin itself"}}},"description":"Every pin in the chat now, oldest first"}}},"example":{"success":true,"pinnedMessages":[{"messageId":"6ad1d0b2c3d4e5f6a7b8c901","pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedAt":"2026-10-16T05:20:31.000Z","notifyMode":"notify","_id":"6ad1d1f8c9daebfc0d1e2f01"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"user_id is not the signed-in person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No chat with that ID, you are not a member of it, no message with that ID in the chat, the message is already pinned, the chat already has 100 pins, or an ID is not valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.update"]}],"x-required-scopes":["chat.messages.update"]}},"/unpinMessage":{"post":{"tags":["Messages"],"summary":"Unpin a message","description":"Unpins a message: in a group a group admin or whoever pinned it may, in a direct chat only whoever pinned it. A notice \"<name> unpinned a message\" is always posted in the chat from you, the other members get a push notification, and everyone in the chat sees it live.\n\n**Permission:** `chat.messages.update` (Edit messages).","operationId":"unpinMessage","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"chat_id":{"type":"string","description":"ID of the chat","examples":["6ad1d0a1c2b3a4f5e6d7c801"]},"message_id":{"type":"string","description":"ID of the pinned message","examples":["6ad1d0b2c3d4e5f6a7b8c902"]},"user_id":{"type":"string","description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","examples":["66f1b2c3d4e5f60718293a4b"]}},"required":["chat_id","message_id","user_id"]}}}},"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"pinnedMessages":{"type":"array","items":{"type":"object","properties":{"messageId":{"type":"string","description":"ID of the pinned message"},"pinnedBy":{"type":"string","description":"ID of the member it was pinned as"},"pinnedAt":{"type":"string","format":"date-time","description":"When it was pinned"},"notifyMode":{"type":"string","description":"notify when the chat was told about the pin, silent when it was pinned quietly"},"_id":{"type":"string","description":"ID of the pin itself"}}},"description":"The pins left in the chat, oldest first"}}},"example":{"success":true,"pinnedMessages":[{"messageId":"6ad1d0b2c3d4e5f6a7b8c901","pinnedBy":"66f1b2c3d4e5f60718293a4b","pinnedAt":"2026-10-16T05:20:31.000Z","notifyMode":"notify","_id":"6ad1d1f8c9daebfc0d1e2f01"}]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"user_id is not the signed-in person","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"No chat with that ID, you are not a member of it, the message is not pinned, you may not unpin it (in a group only a group admin or whoever pinned it; in a direct chat only whoever pinned it), or an ID is not valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.messages.update"]}],"x-required-scopes":["chat.messages.update"]}},"/chat/{chat_id}":{"delete":{"tags":["Chats"],"summary":"Delete a chat","description":"Deletes a chat and every message in it, for everyone. A group can be deleted only by one of its admins who is still a member; any other chat (a direct or comment chat) by any of its members. Members see it disappear live and on their next sync. Rooms owned by Spaces or another app cannot be deleted here. Refusals answer with status 500 and the reason in error.\n\n**Permission:** `chat.chats.delete` (Delete chats).","operationId":"deleteChat","parameters":[{"name":"chat_id","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat. This route spells it chat_id; most Chat routes call the same ID chatId","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"user_id","in":"query","required":true,"schema":{"type":"string"},"description":"Your own user ID (principal.id from GET /api/principal/me on Kazee sign-in); it must be the signed-in person","example":"66f1b2c3d4e5f60718293a4b"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"message":{"type":"string","description":"A confirmation sentence"}}},"example":{"success":true,"message":"Chat and all associated messages deleted successfully"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"user_id is not you, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"$ref":"#/components/responses/NotFound"},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"Refused, with the reason in error: no chat with that ID, it is a space or meeting room (archive it in Spaces), another app manages it, you are not one of its admins (group) or not a member (other chats), or chat_id is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.chats.delete"]}],"x-required-scopes":["chat.chats.delete"]}},"/chat/{chatId}/integrations/{integrationId}":{"delete":{"tags":["Chats"],"summary":"Remove an app from a chat","description":"Takes an app off a group, so it can no longer post there. Only an admin of the group who is still a member may. Removing an app that is not there changes nothing and still succeeds.\n\n**Permission:** `chat.chats.update` (Update chats).","operationId":"removeChatIntegration","parameters":[{"name":"chatId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the chat","example":"6ad1d0a1c2b3a4f5e6d7c801"},{"name":"integrationId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the app login to remove","example":"6ad1d1dae1f2a3b4c5d6e701"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"integrations":{"type":"array","items":{"type":"object","properties":{"integrationId":{"type":"string","description":"ID of the app login in Kazee sign-in (Central)"},"principalId":{"type":"string","description":"The app's user ID in Chat: the sender of what it posts"},"name":{"type":"string","description":"The app's name"},"addedBy":{"type":"string","description":"ID of the admin who added it, or null"},"addedAt":{"type":"string","format":"date-time","description":"When it was added, or null"}}},"description":"The apps left on the chat; empty when none are left"}}},"example":{"success":true,"integrations":[{"integrationId":"6ad1d1dae1f2a3b4c5d6e702","principalId":"6ad1d1ebf2a3b4c5d6e7f802","name":"NOC router alarms","addedBy":"66f1b2c3d4e5f60718293a4b","addedAt":"2026-10-10T11:00:00.000Z"}]}}}},"400":{"description":"chatId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You are not an admin of this group who is still a member, or the call was made with a service or app token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No chat with that ID that you are a member of","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"$ref":"#/components/responses/ServerError"}},"security":[{"kazee":["chat.chats.update"]}],"x-required-scopes":["chat.chats.update"]}},"/stories/{storyId}":{"delete":{"tags":["Stories"],"summary":"Delete my story","description":"Deletes one of your stories at once, with its comments and its file. Everyone who shares a chat with you sees it go live. Only the person who posted it can delete it.\n\n**Permission:** `chat.stories.delete` (Delete stories).","operationId":"deleteStory","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf201"},{"name":"userId","in":"query","required":false,"schema":{"type":"string"},"description":"Ignored: you are always the one deleting. Older apps still send it","example":"66f1b2c3d4e5f60718293a4b","deprecated":true}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"}}},"example":{"success":true}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"The story is not yours","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No story with that ID, or it has already disappeared","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.stories.delete"]}],"x-required-scopes":["chat.stories.delete"]}},"/stories/{storyId}/comments/{commentId}":{"delete":{"tags":["Stories"],"summary":"Delete a story comment","description":"Deletes a story comment; deleting a comment also deletes its replies. Open to the comment's author and the story's owner. Everyone who can see the story sees it go live. Deleting a comment that is already deleted answers success and changes nothing.\n\n**Permission:** `chat.comments.delete` (Delete comments).","operationId":"deleteStoryComment","parameters":[{"name":"storyId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the story","example":"6ad1d0e5f6a7b8c9daebf202"},{"name":"commentId","in":"path","required":true,"schema":{"type":"string"},"description":"ID of the comment or reply","example":"6ad1d1a7b8c9daebfc0d1e01"}],"responses":{"200":{"description":"Done","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","description":"Always true when it worked"},"commentId":{"type":"string","description":"ID of the deleted comment; absent if it was already deleted"},"cascadedReplyIds":{"type":"array","items":{"type":"string"},"description":"IDs of its replies, deleted with it; empty for a reply or a comment with none. Absent if it was already deleted"}}},"example":{"success":true,"commentId":"6ad1d1a7b8c9daebfc0d1e01","cascadedReplyIds":["6ad1d1a7b8c9daebfc0d1e02"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"description":"You neither wrote the comment nor posted the story","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No story with that ID (or it has disappeared), or no such comment on it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"$ref":"#/components/responses/InvalidInput"},"500":{"description":"storyId or commentId is not a valid ID","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"security":[{"kazee":["chat.comments.delete"]}],"x-required-scopes":["chat.comments.delete"]}}},"components":{"schemas":{"Error":{"type":"object","description":"Every error reply. The HTTP status says what kind of error it is.","properties":{"error":{"type":"string","description":"What went wrong, in words"}},"required":["error"]}},"responses":{"BadRequest":{"description":"The request was refused, for example an ID in the wrong form","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"No sign-in, or the token has expired","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Signed in, but without the permission or access this needs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Nothing found with that ID, or you cannot see it","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"InvalidInput":{"description":"A required input is missing or an input is not valid","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"ServerError":{"description":"Something went wrong on our side","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}},"securitySchemes":{"kazee":{"type":"http","scheme":"bearer","bearerFormat":"Kazee token","description":"Send `Authorization: Bearer <token>` with a token from Kazee sign-in."}}},"security":[{"kazee":[]}],"x-tagGroups":[{"name":"Talk","tags":["Chats","Messages","Threads","Chat folders","Media & files","Stories"]},{"name":"Calls & meetings","tags":["Calls","Meetings"]},{"name":"People","tags":["People","Settings","Attendance"]},{"name":"Find","tags":["Search","Notifications"]},{"name":"Bots & apps","tags":["Bots","Apps"]},{"name":"More","tags":["Company settings"]}],"servers":[{"url":"https://chat.inet.africa/api"}]}