SMeetBot API

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 /help or /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 topics and /help@bot_username topics reach that bot as the plain text /help topics, exactly as in a private chat. A bare /help reaches 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 message updates, 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:

PermissionAllows
read_all_messagesReceive every new human message instead of addressed messages only
can_send_messagesSend messages and files in a group or topic
can_edit_messagesEdit messages authored by this bot
can_delete_messagesDelete messages in the group or topic
can_pin_messagesPin and unpin messages
can_restrict_membersRemove a member, except the owner and the bot itself
can_post_messagesPublish 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.

JSON
{
  "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_revision changes 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 a my_chat_member update), running switched off in the organisation, the bot's account removed from the space.
  • installation_generation changes 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.

JSON
{
  "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):

JSON
{"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"}}
  • role is group_owner (the group's current owner) or group_member (a member of the group whom the bot knows there). Both must be active members of the group's space.
  • chat_id is 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_generation and expected_access_revision inside the object pin the installation in that group.
  • A role that does not hold gets 403 INITIATOR_NOT_AUTHORIZED with "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 inside initiator gets 400 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:

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.