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:
- Install checklist grants the action (or
administratoris ticked — full guild set). - Role / channel engine allows it (
botGuildPermissions+ channel overwrites via installrole_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
administratorormanage_rolesto others (hierarchy)
Hierarchy
A worker cannot mute, kick, or ban:
- The room creator
- An OHG human admin (
creator_idoradmin_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, orMarkdownV2. - Inline keyboard: max 8 rows × 8 buttons. Button text and
callback_dataare 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.
Developer packs (recommended grants)
| 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 |
Related
- Bot API
- Bot API methods (all 151, individually)
- Developer overview
- Bots (product)
- Groups · Communities
- Sealed vs shared