SMeet Bot API
Groups, topics and channels
A group owner installs a bot and chooses exactly what it can see and do. Reading every new message is a separate, visible option and is off by default.
Installing a bot#
Open the group or channel information, choose Bots, and add a bot by its @username. The bot must belong to the same SMeet space. Every member can see installed bots and their permissions; only the group owner can add, change or remove them in the current group-role model.
Installation adds the bot account to the group and sends it a my_chat_member update with status member. Removing the bot sends status left and immediately cancels every pending and FAILED update from that group. A direct removal from the member list has the same effect.
Message visibility#
See all new messages (read_all_messages) is an explicit installation option. It is off by default.
- When it is off, the bot receives a human message only when it gives that bot a command (
@bot_username /helpor/help@bot_username), mentions@bot_username, or replies to one of the bot's messages. - When it is on, the bot receives every new human message in the group and its topics, except a message plainly addressed to another bot.
- In a group a command names its bot.
@bot_username /help topicsand/help@bot_username topicsreach that bot as the plaintext/help topics, exactly as in a private chat. A bare/helpreaches no bot, whatever its permissions: with two bots in a room it would otherwise wake both. - The setting never reveals old history. Messages sent before installation or before enabling the option are not replayed.
- Messages from bots and system events are not delivered as ordinary
messageupdates, preventing bot-to-bot loops.
Changing permissions produces another my_chat_member update. Turning a permission off also cancels queued events that depended on the old grant.
Independent permissions#
Permissions do not imply one another:
| Permission | Allows |
|---|---|
read_all_messages | Receive every new human message instead of addressed messages only |
can_send_messages | Send messages and files in a group or topic |
can_edit_messages | Edit messages authored by this bot |
can_delete_messages | Delete messages in the group or topic |
can_pin_messages | Pin and unpin messages |
can_restrict_members | Remove a member, except the owner and the bot itself |
can_post_messages | Publish in a channel |
Every Bot API call checks the current grant again. A revoked grant fails with GROUP_BOT_PERMISSION_DENIED; a removed installation looks unavailable and queued data is not resurrected by retry.
Chat and topic identity#
Group updates use chat.type: "group"; channel updates use "channel". chat.id is the value to pass back as chat_id. A topic has its own chat id and also carries group_id and topic_id, so queues and replies stay inside the topic.
{
"id": "9302",
"type": "group",
"group_id": "84",
"title": "Support",
"topic_id": "7"
}The same message, edit, deletion, file and callback payloads used for private chats work in groups. Buttons can be pressed by current group members.
Installation generation#
Group and channel chats carry installation_generation next to access_revision (since version 1.2.0, capability access_revisions). One installation serves the group and all its topics, so they share both values.
access_revisionchanges whenever the bot's right in the group changes: a grant taken away or given back, the group turned into a channel or back (with amy_chat_memberupdate), running switched off in the organisation, the bot's account removed from the space.installation_generationchanges only when the bot is installed again after a removal. Settings and subscriptions of the old installation should not move to the new one by themselves: ask the owner again.
Pass them back as expected_access_revision and expected_installation_generation; a change in between gives 409 ACCESS_REVISION_CONFLICT or 409 INSTALLATION_GENERATION_CONFLICT (Conditional requests). A bot that publishes to a channel by a subscription keeps the values of the moment the owner set it up, not of the latest update, so an old subscription stops after the grant was taken away and given back.
Chat context#
getChatContext reads one chat as it is now, with its revisions: the group's owner, the installation's permissions and installed_at for a group, topic or channel; the person and the status for a private chat. With user_id it also says whether that person is known to the bot in the group (the owner, or someone the bot received an update from since the current installation), a member and the owner.
{
"chat": {"id": "90012", "type": "group", "group_id": "9001", "title": "Support",
"topic_id": "31", "access_revision": "184502", "installation_generation": "184499"},
"space": {"id": "1", "kind": "public"},
"group": {
"owner": {"id": "52", "display_name": "SMeet", "username": "smeet_admin", "is_bot": false},
"permissions": {"read_all_messages": false, "can_send_messages": true, "can_edit_messages": true,
"can_delete_messages": false, "can_pin_messages": false,
"can_restrict_members": false, "can_post_messages": false},
"installed_at": "2026-10-01T09:00:00Z"
},
"user_check": {"user_id": "5002", "known": true, "is_member": true, "is_owner": false}
}Use it when a person in one chat decides about another, for example the owner sets up a channel from the private chat: read the channel's revisions before showing the confirmation, keep them with the confirmation, and pass them with the action. It is a read without locks and out of date at once; what makes an action safe is the condition of the call. A person the bot has not received anything from is "known": false, and the method reveals nothing else about them. Limit: 5 calls a second per bot, bursts of 10.
Acting for a person: initiator#
initiator makes a changing call depend on a person's role in a group at the moment of the call (capability initiator_conditions):
{"chat_id": "70051", "text": "Hello! We have checked your request.",
"expected_access_revision": "184467",
"initiator": {"user_id": "5002", "role": "group_member", "chat_id": "90010",
"expected_installation_generation": "184499"}}roleisgroup_owner(the group's current owner) orgroup_member(a member of the group whom the bot knows there). Both must be active members of the group's space.chat_idis a group, topic or channel of the bot. When the call's own chat is in a group, the initiator's chat is the same group; when the call goes to a private chat, it may be any group of the bot.expected_installation_generationandexpected_access_revisioninside the object pin the installation in that group.- A role that does not hold gets
403 INITIATOR_NOT_AUTHORIZEDwith"field": "initiator.user_id", the same answer for every reason, so it tells nothing about a person the bot does not know. An unknown field insideinitiatorgets400 INVALID_REQUEST.
Typical uses: a helpdesk operator's answer to a customer, sent only while the operator is still in the support group; a member removed or a message deleted by the owner's button in a moderation card, with the revisions of the violation and "role": "group_owner".
Channels#
A channel installation uses can_post_messages, not can_send_messages. The bot is never made the channel owner. Every bot post keeps the bot as its technical author in the audit log, while clients display it according to the channel UI. Installing a bot does not expose the channel's subscriber list.
Moderation methods#
All mutating calls require an Idempotency-Key:
- deleteMessage deletes a message when
can_delete_messagesis granted; in private chat it can only retract the bot's own message. - pinChatMessage and unpinChatMessage need
can_pin_messages. - restrictChatMember needs
can_restrict_membersand removes the selected member.
Backpressure and gaps#
If a bot stops keeping up, SMeet does not let one noisy group consume its whole queue. It may stop enqueuing new group messages and later send one delivery_gap update with the number and time range of dropped messages. The dropped texts are not included. Treat the gap as a reason to resynchronise your own state or ask a person to repeat an action; Bot API does not grant history access.