Bot API
Who this is for: developers with a Forge token (bzbot_…) who want to receive updates and reply as their bot.
Console: developers.buzzio.dev · Product: Bots · Workers: Worker bots
This API copies Telegram’s developer experience (token, methods, { ok, result }), not Telegram’s whole product. There is no Buzzio file CDN, no sealed-chat access, and no acting as a person.
Quick start
- In the app:
@forge_bot→/newbot→ Service → copybzbot_…once. - On desktop: paste the token on developers.buzzio.dev.
- Terminal:
getMe→ leavegetUpdatesrunning → click Test /start on the site →sendMessagea welcome. - Submit when Test passes. Approved + active plan → real users can Start.
Seed / 12-word phrase never goes on the website. The token is the bot login.
What you can do
| Job | Method |
|---|---|
| Check the token | getMe |
| Poll for user messages (no public URL) | getUpdates |
| Reply with text | sendMessage |
| Reply with photo / video / audio / file URL you host | sendPhoto / sendVideo / sendAudio / sendDocument |
| Push updates to your HTTPS server | setWebhook |
| Stop webhook, return to polling | deleteWebhook |
| See webhook status | getWebhookInfo |
| Show / hide a typing pill | sendChatAction |
| Inline buttons | reply_markup on send, then answerCallbackQuery |
| Edit or delete a bot message | editMessageText / editMessageCaption / editMessageMedia / editMessageReplyMarkup / deleteMessage / deleteMessages |
| Copy or forward in this bot DM | copyMessage / forwardMessage |
| Composer slash list | setMyCommands / getMyCommands / deleteMyCommands |
| Display name / bio / search subtitle | setMyName / setMyDescription / setMyShortDescription |
| Profile photo (HTTPS URL they host) | setMyProfilePhoto / removeMyProfilePhoto |
| Chat menu (commands or Mini App URL) | setChatMenuButton / getChatMenuButton |
| Animation / voice / video note / sticker | sendAnimation / sendVoice / sendVideoNote / sendSticker (URL or bzstk_…) |
| Bot-owned sticker set | createNewStickerSet / getStickerSet / uploadStickerFile |
| Installs / stats / 7-day history / report / schedule | getMyInstalls / getBotStats / getChatHistory / reportMessage / sendScheduledMessage |
| Location / venue / contact card | sendLocation / sendVenue / sendContact |
| Poll, dice, album, checklist | sendPoll / stopPoll / sendDice / sendMediaGroup / sendChecklist |
| Confirmable choices | sendChoice |
| Live photo / streaming draft / live pin | sendLivePhoto / sendMessageDraft / editMessageLiveLocation |
React / vanish / rich blocks / getFile |
setMessageReaction / ephemeral edits / sendRichMessage / getFile |
You cannot: read sealed 1:1 chats, Whisper private chat, Whisper Questions, or E2E groups; upload bytes for Buzzio to host; or use a service token as a worker (and the reverse). Payments, checkout, invoices, pay buttons, paid media, Stars, gifts, paid reactions, and subscriptions are permanently not offered: method names return 404, while equivalent fields, buttons, and rich blocks return 400 validation errors.
Base URL and auth
Host: https://developers.buzzio.dev
Telegram-style (primary):
https://developers.buzzio.dev/bot<token>/<method>
Example: https://developers.buzzio.dev/botbzbot_…/getMe
Also accepted (Bearer):
POST https://developers.buzzio.dev/v1/sendMessage
Authorization: Bearer <token>
Content-Type: application/json
Same pattern for /v1/getMe, /v1/getUpdates, and other methods.
Do not put the token in a ?token= query string (access logs). Path or Bearer only.
How to call
HTTPS. UTF-8. GET or POST.
Parameters from, in order (later wins):
- URL query string
application/x-www-form-urlencodedapplication/json
Reject multipart/form-data file uploads. Outgoing media is an HTTPS URL you host, or a bzstk_… file_id from a set this bot registered. Incoming user media is a 7-day bzfile_…. Buzzio never GETs your URL (SSRF lock).
Success / error envelope
Success:
{ "ok": true, "result": { } }
Failure:
{ "ok": false, "error_code": 401, "description": "Unauthorized" }
| HTTP | error_code |
When |
|---|---|---|
| 401 | 401 | Bad / missing / rotated token |
| 403 | 403 | Shadow-banned, suspended, plan expired, user hid the bot |
| 400 | 400 | Bad chat_id, empty text, file bytes, bad URL |
| 404 | 404 | Unknown method, unknown chat_id |
| 409 | 409 | getUpdates while a webhook is set |
| 429 | 429 | Rate limit |
Older /v1/sendMessage responses may also include "error": "…" alongside description for compatibility.
Two ways to receive updates
One at a time (same rule as Telegram):
┌─ webhook URL set → Buzzio POSTs Update to you
User taps Start ───┤
└─ no webhook → you poll getUpdates
| Mode | When | Public URL? |
|---|---|---|
Polling getUpdates |
Laptop, first bot, CI | No |
Webhook setWebhook |
Always-on server | Yes (HTTPS) |
If a webhook is set, getUpdates returns 409 (Conflict: can't use getUpdates while webhook is active).deleteWebhook restores polling.
Pending polling updates: keep about 24 hours, then drop. Cap about 1000 per bot; drop oldest.
Website Test /start and a real user Start use the same Update shape. A terminal bot that answers Test will answer a real user.
Platform `/start`
Buzzio owns the Start button and the start event. You own the welcome text.
| Layer | Owner |
|---|---|
| Start button in the app | Buzzio |
POSTing /start to you |
Buzzio |
Welcome sendMessage after Start |
You |
Other commands (/help, /weather, …) |
You |
Do not invent a custom “type hi to begin” as the only entry — users learn one Start for every bot.
Available methods
The Bot API publishes 151 HTTP methods. Each one is documented individually — heading, “Use this method to…”, then a Parameter / Type / Required / Description table — on Bot API methods. That is the same layout as Telegram Bot API.
Console copy (searchable, one page): developers.buzzio.dev/docs/api/.
| Status | Names |
|---|---|
| Live | Waves 0–H and J (getMe, send*, edit*, stickers, room moderation, invites, forum/channels, native ops, …) |
| Documented, not enabled | Wave I: stories, inline queries, Mini App answers, games, logOut / close. Calls return 404. |
| Permanently not offered | Payments, checkout, invoices, pay buttons, paid media, Stars, gifts, paid reactions, subscriptions, and bot premium (setMyPremium, grantUserPremium, …). Method names return 404; equivalent request fields/controls fail validation. |
chat_id is always a string. Outgoing media is an HTTPS URL you host; Buzzio never GETs it. Incoming user media is a 7-day bzfile_…. Forum topic methods create and manage community channels (message_thread_id is the channel id).
Worker grants: Worker bots.
JSON types
Update
{
"update_id": 17,
"message": { }
}
update_id is a positive integer, sequential per bot (needed for offset).
Wave A also delivers callback_query when a user taps an inline button, and start_parameter on /start <payload> (also in message.text). Interactive sends also deliver choice_answer, poll_answer, and—only for developer-mode checklists—checklist_update.
Wave F delivers chat_join_request when someone asks to join a room that requires approval:
{
"chat_join_request": {
"chat": { "id": "ohg:…", "type": "group", "title": "Mods" },
"from": { "id": "bu_…", "is_bot": false, "first_name": "User" },
"date": 1710000000,
"invite_link": { "invite_link": "https://links.buzzio.dev/join?g=…&t=…" }
}
}
User
{
"id": "bu_a1b2c3…",
"is_bot": false,
"first_name": "User"
}
You do not receive the person’s Buzzio ID, Buzzio username, or avatar. id is a bot-scoped opaque handle (bu_…) stable for that person talking to your bot only — different bots get different ids for the same person. first_name is generic "User". Forge analytics stay counts-only.
Chat
{
"id": "botdm_<botId>_<opaqueSuffix>",
"type": "private"
}
Service-bot v1: type is always "private". The chat id never embeds a Buzzio ID.
Message
{
"message_id": "msg_…",
"from": { "id": "bu_…", "is_bot": false, "first_name": "User" },
"chat": { "id": "botdm_…", "type": "private" },
"date": 1710000000,
"text": "/start",
"chat_id": "botdm_…",
"command": "start"
}
| Field | Why |
|---|---|
chat.id |
Telegram style |
chat_id |
Kept for playground / echo samples |
command |
Platform Start ("start") so you cannot miss it |
text |
"/start" or "/start <payload>" |
start_parameter |
Present when the user opened me.buzzio.dev/<bot>?start= or buzzio://bot?u=&start= |
| User → bot | Text, plus incoming photo/voice/file as file_id (7 days) |
| Bot → user media | URL metadata on outgoing messages |
photo / voice / … |
Incoming attachment fields on the Update |
poll_answer |
User voted on a bot poll |
choice_answer |
User confirmed or cancelled a sendChoice card |
checklist_update |
A checklist item changed when update_mode is developer |
Unix date is seconds.
Interactive messages
Buttons and keyboards
reply_markup inline keyboards allow at most 8 rows × 8 buttons. Button text is 1–64 characters and each button must have exactly one action: callback_data (1–64), an HTTPS url, copy_text.text (1–256), or disabled: true. Optional style is primary, success, or danger.
Reply keyboards allow at most 12 rows × 12 text buttons (1–64). Supported modifiers are resize_keyboard, one_time_keyboard, is_persistent, input_field_placeholder (1–64), and selective; remove_keyboard and force_reply are also supported. Unsafe Telegram button fields, including web_app, login/inline-switch/request fields, games, pay buttons, and all commerce fields, return 400.
Callback taps are accepted only when the value exists on that live bot-owned message and the button is enabled. They expire after 30 seconds, duplicate taps are deduplicated within that window, and each user/chat is limited to 20 callbacks/minute. answerCallbackQuery is idempotent; unknown or cross-bot ids return 404 and expired ids return 410.
`sendChoice`
Service-bot DMs can send a native confirmable choice:
question(ortext/title): 1–4000 characters.options: 2–10 strings or{ id, text }objects. Text is 1–100; ids are unique 1–64-character letters/numbers/underscore/hyphen and default toopt_1,opt_2, …- Single is the default.
mode: "multi"/"multiple"or a supported multiple flag enables multi-select. min_selecteddefaults to 1;max_selecteddefaults to 1 for single and option count for multi.confirm_label/cancel_label: max 64. Expiry is 1 minute–7 days viaexpires_ator whole-secondexpires_in.
The Message choice payload contains the normalized fields plus kind: "choice", title, selected_option_ids, and status. The app saves each selection first, then submits Confirm or Cancel. Confirm enforces min/max; repeated submit is idempotent. Final submission changes payload status to submitted or cancelled and emits:
{
"choice_answer": {
"choice_id": "msg_…",
"message_id": "msg_…",
"user": { "id": "bu_…", "is_bot": false, "first_name": "User" },
"option_ids": ["opt_1"],
"cancelled": false,
"chat_id": "botdm_…"
}
}
Polls and checklists
Polls have a 1–300-character question and 2–10 options of 1–100 characters. Regular polls are single-answer unless allows_multiple_answers: true; quiz polls are always single-answer, require 0-based correct_option_id, and may include a 200-character explanation revealed after answering. open_period is 5–600 seconds; close_date is Unix seconds/ms 5–600 seconds ahead; use one, not both. A changed selection replaces the previous vote and emits poll_answer; unchanged submissions are idempotent. Closed/timed-out polls return 410.
Checklists have a 1–200-character title and 1–30 items. Item text is 1–120; optional stable ids use the same 1–64 safe-id rule. update_mode: "client" is the default and does not notify the bot. update_mode: "developer" (also developer_updates: true / notify_bot: true) emits checklist_update only when a value actually changes. It includes nested actor, message, item, and state, plus flat chat_id, message_id, item_id, and done.
Rich blocks
sendRichMessage accepts 1–30 blocks and a maximum serialized payload of 64 KiB. In addition to heading, paragraph, list, and table, it supports:
collapsible: title 1–120, text 1–4000, optionalinitially_expanded; max 10.media: photo/video/audio/document HTTPS URL (max 2048), caption max 1000, alt text max 300, optional declared size 1–20 MiB; max 10.actions: safe inline buttons. Collapsible/media blocks may also embed actions; max 20 embedded actions total and 1–8 per block.
Commerce/payment/invoice/paid-media/Stars/gift/subscription blocks or fields return 400.
Webhook POST (Buzzio → you)
When a webhook is set, Buzzio POSTs one Update (same JSON as getUpdates items):
POST https://your-server/webhook
Content-Type: application/json
X-Buzzio-Timestamp: …
X-Buzzio-Bot-Id: …
X-Buzzio-Signature: sha256=…
Verify the signature before trusting the body. Return HTTP 2xx quickly, then call sendMessage asynchronously if needed.
Probe payloads from the console may include "probe": true — ignore for real chats.
Terminal walkthrough
# 1. Token from Forge /newbot (vanishes after 5 minutes)
# 2. Who am I?
curl.exe -sS https://developers.buzzio.dev/botbzbot_TOKEN/getMe
# 3. Wait for messages (leave running)
curl.exe -sS "https://developers.buzzio.dev/botbzbot_TOKEN/getUpdates?timeout=20"
# 4. After an Update arrives:
curl.exe -sS -X POST https://developers.buzzio.dev/botbzbot_TOKEN/sendMessage `
-H "Content-Type: application/json" `
-d "{\"chat_id\":\"botdm_…\",\"text\":\"Hi, I am Weather Bot.\"}"
Loop in a script: offset = last update_id + 1 so you do not see the same Update twice.
Test without a public server: start the poll loop first, then click Test on the website. Buzzio queues /start; your script sendMessages the welcome; Test passes; you can Submit.
Always-on later: setWebhook with your HTTPS URL, stop polling.
What stays on the website / Forge
| Still website / Forge only | Why |
|---|---|
| Create bot, username | Identity = Buzzio ID on the phone |
| Show token 5 min / reset | Forge /@yourbot api reset |
| Submit for review | ToS + review ping |
| Pay / renew | No card on the Bot API |
| Staff ban | Founder desk |
setWebhook on the API is allowed. Console save-webhook is the same field.
Limits
| Rule | Value |
|---|---|
| User → bot | ~30 / minute / chat |
sendMessage |
~60 / minute / bot |
| Text | 4000 chars |
| Media | HTTPS URL you host; Buzzio never fetches |
getUpdates timeout |
0–25 s |
| Polling queue | ~24 h, max ~1000 |
sendChoice |
2–10 options; 1 min–7 day expiry |
| Poll | 2–10 options; timed close 5–600 s |
| Checklist | 1–30 items |
| Rich message | 30 blocks / 64 KiB; 10 media; 10 collapsibles; 20 actions |
| Callback tap | 30 s lifetime; 20/min/user/chat |
| Live send | Approved + plan active (test chats botdm_test_* allowed while testing) |
chat_id |
Only botdm_test_* or botdm_<thisBotId>_<ghostId> for service bots |
| Sealed / person ids | 400 |
Shadow-ban / suspend: webhook paused; sendMessage 403; getUpdates empty or 403.
Abuse and quotas are keyed by owner Buzzio ID and by bot. Ban the person → their bots go offline.
Telegram mapping
| Telegram | Buzzio |
|---|---|
api.telegram.org/bot<token>/METHOD |
developers.buzzio.dev/bot<token>/METHOD |
{ "ok": true, "result": … } |
Same |
getUpdates xor webhook |
Same |
| Integer chat ids | Strings (botdm_…, ohg:…, community:…) |
sendPhoto by URL |
Same idea; URL only, never multipart |
| Groups | Worker token after Accept + grant |
Incoming file_id |
7-day hold, not a public CDN |
| Per-method pages | Bot API methods |
Intentionally not here
| Item | Why |
|---|---|
bot-api.buzzio.dev hostname |
Nice alias; not required |
| Official client libraries | After Wave I |
| Developer-hosted file CDN | Cost lock: outgoing media stays URL-only |
| Payments, checkout, invoices, pay buttons, paid media, Stars, gifts, paid reactions, subscriptions | Permanently not offered; method names return 404 and equivalent fields/controls return validation errors |
| Wave I (stories, inline, games, session) | Names documented; calls return 404 |
Worker room grants: Worker bots. Full method tables: Bot API methods.
Related
- Developer overview
- Bot API methods (all 151, individually)
- Worker bots
- Bots (product)
- Legal and policies