BuzzioDocs

Worker bots

Who this is for: developers building moderation / automation tools for open-history groups and Communities, and admins who request installs.

Service (1:1) bots: Bot API · Product: Bots · Console: developers.buzzio.dev


Why two kinds

Service Worker
Discovery People search @weather_bot Not in people search or 1:1 dashboard
Surface Start → DM Room Bots tile / /bots
Token Separate Separate — kind locked at Forge create
Install User Starts Admin requests → developer Accepts

One token that can spam every Starter and kick members is a worse leak. Need both jobs? Create two bots.

Never: sealed 1:1, Whisper private chat, Whisper Questions, E2E groups. Never: dump a bot into OHG admin_ids. Never: install the instant an admin taps Add — Accept on Console first. Community administrator / manage_roles are creator-controlled (off by default; only when the installer ticks them). Payments, checkout, invoices, pay buttons, paid media, Stars, gifts, paid reactions, and subscriptions are permanently not offered: method names return 404 and equivalent worker payload fields return validation errors.


Install flow

Person (phone, seed stays there)
        ↓
Search @forge_bot → /newbot → Worker
        ↓
display name + @username + API token (copy once)
        ↓
Not in people search. Not on 1:1 dashboard.
        ↓
Developer links the worker token on developers.buzzio.dev
        ↓
OHG or Community → Bots tile → lookup @mod_bot
        ↓
Admin picks permissions / roles → Request  (room shows Pending)
        ↓
Console → Requests → Accept or Reject
        ↓
Only after Accept: bot is in the room; server gets events; API checks grants

Pending requests do not count as installed. Reject → bot never joins. Same token cannot Start a 1:1.

Console Requests lists pending for every linked worker (bot name on each card). Accept/reject requires the signed-in developer who linked that bot. The phone Bots screen cannot Accept for the developer.


Who may request, edit, remove

Room Who
Open-history group Creator (super admin) or anyone in admin_ids
Community Creator, adminIds, or a role with Administrator

Members cannot send a request. The developer cannot accept by pasting a token into the room.

Platform `/bots` slash

Admins only. Never forwarded to the worker webhook (or a worker could fake an add).

/bots
/bots add mod_bot
/bots perm mod_bot delete on
/bots remove mod_bot

/bots add is still a request. Members who type /bots get “Only admins can use /bots” and the text is not sent to the room.

Later permission ticks can live on the Bots screen or /bots perm without a full re-Accept for every toggle (product: ticks are live after install).


OHG permissions (checklist)

OHG humans stay binary admins (admin_ids). Bots must not use that list. Grants live on the install, per group, per bot_id.

Default on the request: Read messages + Send messages. Everything else off until ticked.

Permission Meaning
Read messages See messages (needed for commands)
Send messages Post as the bot
Delete messages Delete other people’s messages
Pin messages Pin / unpin
Timeout / mute Restrict a member for a time in this OHG
Kick Remove from this OHG
Ban Ban from this OHG — not a global Buzzio ban
View members Member list if the group hides it from members
Approve joins If join approval is on

If the OHG is admins-only send, Send on the bot still allows it to post (it is a tool, not a member). It still cannot do unticked admin actions.


Community permissions

Use the same Community role checklist as humans. On the request, the admin ticks grants and may attach extra roles for channel view/send. Defaults: all checklist ticks off (including Administrator). The creator (or an admin with Administrator) may grant administrator or manage_roles if they fully trust the bot.

Dual gate (every API call)

A worker method succeeds only when both are true:

  1. Install checklist grants the action (or administrator is ticked — full guild set).
  2. Role / channel engine allows it (botGuildPermissions + channel overwrites via install role_ids + bot integration role).

Extra human roles on the install affect channel visibility/send. Guild API grants still require the matching checklist tick unless Administrator is on.

Community grant → methods

Grant Unlocks
(channel send after view) sendMessage / media / sticker
delete_other_messages deleteMessage, deleteMessages
administrator Full guild set + bypass channel locks; deleteChatHistory
pin_messages Message pins + topic unpin-all
can_pin_channel pinChannel / unpinChannel
manage_members Timeout / kick / ban / tags
manage_roles Role CRUD + assign roles below the bot
view_members Member list when hidden; listChatMembers / search
can_tag @everyone / @here / mentions
bypass_slow_mode / slow_mode Bypass / set restricted messaging
create_channels / edit_channels Channel / forum topic create-edit; overwrites
create_categories createCategory
create_events / manage_events Event CRUD
view_audit_logs getAuditLogs
invite_people / temp_invite Invites + join requests
temp_channel_password Channel passwords
modify_description / modify_rules Title, photo, description, rules

Private staff channel: grant the bot’s roles view/send on that channel. Do not give @everyone dangerous mod perms just to make a bot work.


Hard denials (both rooms)

Hide in the UI. Reject on the server even if a client sends them:

  • Super admin / transfer ownership / change creator
  • Promote or demote human admins
  • Add or remove other bots
  • Delete the OHG or community
  • Password, security, encryption, history/boot billing
  • Start a 1:1 / appear in people search
  • Assigning roles that include administrator or manage_roles to others (hierarchy)

Hierarchy

A worker cannot mute, kick, or ban:

  • The room creator
  • An OHG human admin (creator_id or admin_ids)
  • A community member whose highest role is ≥ the bot’s highest assignable role
  • Another worker

Fail with permission denied, not a silent no-op.


Room power vs bot commands

Room permissions (this page): what Buzzio allows this token to do in this room. Enforced on every API call.

Bot commands (your code): /mute @user 10m is a normal message Buzzio forwards. Your server calls restrictChatMember. If Timeout was not granted, Buzzio returns permission denied.

Buzzio does not ship a platform command language for /mute / /ban. You define commands. Buzzio ships API methods.


Worker Bot API

Same host and token style as Bot API. Every method with a parameter table: Bot API methods. Service tokens get 403 on worker methods even with a guessed chat_id. Worker tokens get 403 on 1:1 botdm_* sends.

Methods require: kind = worker, approved, plan active, linked on Console, accepted in that room, and the matching grant. Pending requests do not count:

Method Needs
sendMessage / media URL sends / sendSticker Send (Community stickers also need channel send_sticker)
deleteMessage Delete
pinChatMessage / unpinChatMessage / unpinAllChatMessages Pin
restrictChatMember Timeout
kickChatMember Kick (catalog #140; same grant)
banChatMember / unbanChatMember Ban
banChatSenderChat / unbanChatSenderChat Ban a channel/bot poster — not a ghost_ person
getChat / getChatMember / getChatAdministrators / getChatMemberCount Read (member list: View members if the room hides it)
leaveChat Always (bot leaves this room)
setChatTitle / setChatDescription / setChatPhoto / deleteChatPhoto Manage room info (OHG tick) or Community modify_description
setChatStickerSet / deleteChatStickerSet Room default pack — set must already belong to this bot
setChatPermissions Manage room info — OHG only (can_send_messages, can_see_members)
setChatAdministratorCustomTitle Label on this worker in the room
setChatMemberTag Community only — tag or assign a non-privileged role below the bot
setMyDefaultAdministratorRights / getMyDefaultAdministratorRights Default worker ticks for new installs (creator may include administrator / manage_roles)
editMessageText / caption / reply markup Own bot messages (channel send)
setMessageReaction / sendChatAction Channel view + send
deleteMessages Bulk delete (delete_other_messages for others)
deleteChatHistory Wipe all messages + media (administrator only; community / channel)
getChatChannels / listChatMembers / searchChatMembers Installed + view where gated
getChatRoles / getChatRole / getChatBans Installed; bans need manage_members
createChatRole / editChatRole / deleteChatRole / setChatRolePositions manage_roles
getChatPermissions / editChannelPermissions edit_channels
setMyCommands / getMyCommands / deleteMyCommands Composer slash list (options + scopes)
setMyContextCommands / getMyContextCommands / deleteMyContextCommands Message/user Apps menus
getMyCommandPacks / applyMyCommandPack Starter packs: observer, responder, moderator, builder
answerBotCommandAutocomplete Answer autocomplete_query
createChatInviteLink / editChatInviteLink / revokeChatInviteLink / listChatInviteLinks Extra invite (OHG Approve joins; Community temp_invite / invite_people)
getMyPermissions / getMyInstalls / getChatHistory Live ticks, accepted rooms, 7-day / 100-message window
reportMessage Staff-visible snapshot (same reasons as in-app Report)
exportChatInviteLink Primary invite (OHG Approve joins; Community invite_people)
approveChatJoinRequest / declineChatJoinRequest Admit or deny ghost_… (OHG Approve joins; Community invite_people)
answerChatJoinRequestQuery / sendChatJoinRequestWebApp Join-gate ack + HTTPS Mini App
createForumTopic / editForumTopic / deleteForumTopic Community channel as a topic (create_channels / edit_channels)
closeForumTopic / reopenForumTopic Freeze posting (edit_channels)
unpinAllForumTopicMessages Clear pins in that channel (pin_messages)
hideGeneralForumTopic / unhideGeneralForumTopic / closeGeneralForumTopic / reopenGeneralForumTopic / editGeneralForumTopic / unpinAllGeneralForumTopicMessages Default / welcome channel
getForumTopicIconStickers Allowed topic icon colors

Service tokens get 403 on these methods even with a guessed ohg: / community: chat_id.

chat_id is the OHG id or community id — never a sealed person id, never botdm_*. For a specific channel, use community:{communityId}:{channelId} or pass message_thread_id.

Rate limits still apply. Ban is this room, not the person’s Buzzio account.


Slash commands, scopes, options, Apps menus

Workers register commands with setMyCommands (Telegram-shaped, Discord-capable).

Chat input commands

{
  "commands": [
    {
      "command": "mute",
      "description": "Timeout a member",
      "type": "chat_input",
      "options": [
        { "name": "user", "type": "user", "description": "Member", "required": true },
        { "name": "minutes", "type": "integer", "required": true, "min_value": 1, "max_value": 10080 },
        {
          "name": "reason",
          "type": "string",
          "required": false,
          "choices": [
            { "name": "Spam", "value": "spam" },
            { "name": "Other", "value": "other" }
          ]
        }
      ]
    }
  ]
}

Option types: string, integer, number, boolean, user, channel, role, mentionable.
Static choices (max 25) or autocomplete: true (answer with answerBotCommandAutocomplete).

Members type /mute ghost_1 10 spam (positional) or /mute user:@alice minutes:10. Buzzio emits bot_command with structured options[] plus the raw args string.

Scopes

Pass scope on set/get/delete:

scope.type Meaning
default Room-wide default list (also mirrored to legacy commands)
all_channels Fallback for every community channel
channel Requires channel_id — wins over all_channels / default

Resolution order for a channel: channel scope → all_channels → default → legacy commands.

Context menus (Apps)

{
  "context_commands": [
    { "command": "delete_message", "description": "Delete this message", "type": "message" },
    { "command": "timeout_user", "description": "Timeout this member", "type": "user" }
  ]
}

Or use setMyContextCommands. In the app: message sheet → Apps; long-press a sender name → Apps. Emits bot_command with source: "message"|"user" and target.

Starter packs

getMyCommandPacks / applyMyCommandPack with pack: observer | responder | moderator | builder.
Packs only register command names — your server still calls Bot API methods, and room grants still gate those methods.

Pack Example chat commands Example Apps
Observer help, whoami, channels message_info
Responder ping, say, poll_prompt quote
Moderator mute, kick, purge delete_message, timeout_author, timeout_user
Builder new_channel, new_role —

Interactive room messages

Worker-room interaction is a deliberately smaller surface than service-bot DM interaction. Workers use sendMessage (or a URL media send) with structured fields; sendChoice, service-DM polls/checklists, and sendRichMessage are not worker-room methods.

Common limits:

  • Entire worker message payload: max 30,000 serialized characters; nesting deeper than 8 is rejected.
  • Text: max 4000. parse_mode: HTML, Markdown, or MarkdownV2.
  • Inline keyboard: max 8 rows × 8 buttons. Button text and callback_data are max 64; URL buttons must be HTTPS. Each button has exactly one of callback data or URL.
  • Reply keyboard: max 8 rows × 8 text choices, with one_time_keyboard / resize_keyboard; remove-keyboard and force-reply are supported.
  • Worker-hosted media URL: HTTPS, max 2048 characters. Existing channel-specific send grants still apply.

For a room choice, call sendMessage with payload.type: "choice" and a choice object:

{
  "chat_id": "ohg:…",
  "payload": {
    "type": "choice",
    "prompt": "Deploy now?",
    "choices": [
      { "text": "Yes", "value": "yes" },
      { "text": "No", "value": "no" }
    ]
  }
}

A choice needs a prompt (max 4000) and 2–20 unique choices; each label/value is max 64. Buzzio creates inline buttons when reply_markup is omitted. A normal callback emits callback_query; a choice value emits:

{
  "choice": {
    "id": "event-id",
    "from": { "id": "bu_…", "is_bot": false, "first_name": "User" },
    "message": { "message_id": "…", "chat_id": "ohg:…" },
    "value": "yes",
    "chat_id": "ohg:…"
  }
}

The server accepts an interaction only when the user is still a member, both user and worker can view the Community channel, the worker remains installed/authorized, the value was indexed from that immutable message, and the index digest/expiry still matches. Interaction receipts deduplicate the same user/message/kind/value; failed delivery may be retried safely. The index expires with the room/history retention (OHG default: 365 days) and is removed when the message is deleted. Archived or hidden channels, removed workers, forged values, and stale indexes are rejected.

Worker room messages intentionally do not support copy/disabled/styled buttons, service-DM choice_answer, polls, checklists, rich blocks, commerce, payments, checkout, invoices, pay buttons, paid media, Stars, gifts, paid reactions, or subscriptions.


Events after Accept

Via webhook or getUpdates (after Accept — not when the room only taps Request):

Event Notes
message New message (OHG: read; Community: channel view_channel)
edited_message Text edit fan-out
message with delete_chat_message / deleted payload Message deleted for everyone
callback_query / choice Indexed interaction tap
bot_command Slash or Apps menu; includes options[], source, optional target
autocomplete_query Autocomplete option (answer via answerBotCommandAutocomplete)
chat_join_request OHG Approve joins; Community invite_people
chat_member / my_chat_member Member join / leave / role change
message_reaction Reaction add/remove when room metadata is known
bot_added / bot_removed Install Accept / remove / leaveChat
permissions_changed Live grant or role_ids patch

No 1:1 /start. Remove or leaveChat sends bot_removed and clears the install. Do not expect a dump of room history just because someone requested the bot.

Pack Typical ticks
Observer Channel view + read events + list APIs
Responder Observer + send + edit own + reactions + typing + commands
Moderator Responder + delete/bulk + manage_members + pin + can_tag + view_members
Builder Channels/categories + overwrites + manage_roles + events + invites
Admin (trusted) administrator (creator choice only)

Optional: Console / Forge notice that a request is waiting — that is not a Bot API update.


Privacy label

Shared rooms are already not E2E. Still say it after accept:

This room has a worker bot that can read messages you allow it to see. The bot owner’s server can receive those events.

Show on the Bots screen and once in the room after accept. Pending does not get the label. Missing label after install is a privacy bug.


Troubleshooting

Symptom Try
Lookup finds nothing Worker not approved / not linked, or you typed a service bot username
Stuck on Pending Developer must Accept on Console Requests
API 403 on room method Wrong kind (service token), not accepted, or grant missing
/bots visible to members Should not be — report as a product bug if members can install