Bots
A bot is an account a program runs. Its owner makes it, and it is a user like any other: a Mandarin ID, a profile, the conversations it is in, everybody's privacy and blocks as people have them. What sets it apart is how it is reached: it signs in with a token rather than a phone, and it hears of what happens through a queue of its own rather than connections, over the Bot API (HTTP).
Bots are made and managed through the system bot, in a conversation with it, which works in every client and changes with the server rather than with the clients' releases.
Bot Accounts
- Profile.
profile.getand the members of a conversation mark a bot with"bot": true; a person's carry no such field. A bot's profile also says what it hears of the groups it joins, asbot_reads(see below), for whoever adds it to one to know; a bot among a conversation's members carries what it hears there. - Name. A bot has a public name, which people find it by and its link ends
with:
<link_base>/<name>on a server with a link base, aslinkin its profile. A name is 5 to 32 Latin letters, digits and underscores, starts with a letter and ends inbot, case aside —weather_bot,TetrisBot— and is kept in lower case. The ending is a bot's alone: no invitation is named so, and a name an invitation had before is no bot's to take. A bot keeps its name for good. - Owner. Every bot has one, who alone manages it, up to 20 bots. A bot owns no bots.
- Token.
<bot ID>:<secret>. The system bot tells it to the owner, as a message in their conversation with it, when it makes the bot and when it replaces the token — the owner's to keep safe and, if they like, to delete. Besides, the server keeps only its digest: it is never read back, and replacing it ends the old one at once, and the webhook set with it. - Nothing of a device. A bot has no phone number, no sessions, no address book, and no push registrations.
- The same rules as people. Who may write to a bot first, and who may add it
to a group, is the bot's privacy:
direct_messagesandgroup_invites, as anyone's. A bot answers in the conversations it is in; it starts none, nor is it seen typing in one it has not got — a direct one somebody wrote in. - In groups and channels a bot is a member as anyone is: given a role,
restricted, banned or removed as anyone is, posting as its role lets it — in
a channel, as an admin or an editor — and leaving with
leaveConversation. It owns no conversation.
What a Bot Hears
A bot follows the streams its user would — its account stream and the stream of every conversation it is in, from when it joined — and is told of:
| Event | When |
|---|---|
message.created, message.edited, message.deleted |
What is said, and done to what is said |
message.reacted |
A reaction to a message |
member.added, member.removed |
Who comes and goes |
conversation.created, conversation.deleted |
The bot comes to be in a conversation — saying by whom it was added, as a person is told — or is out of it, and why |
button.pressed |
Somebody pressed one of its buttons |
Reads, deliveries, pins, drafts and the like are for people's devices and never reach a bot. A bot is not told of what it did itself: a message it wrote or edited, deleted, or reacted to.
All of a direct conversation is addressed to the bot. Of a group, the bot hears what its owner chose, publicly, on its profile, as it was when the bot joined — what those who added it saw. Changed later, it holds in the groups the bot joins after; where it is already, it is to be added again to take it up.
addressed(the default): a message that mentions the bot or answers one of its messages — which is how a person is addressed too — and what is done to its own messages: reactions, deletion. A message deleted for everybody no longer says whom it mentioned, so of other deletions it hears nothing; one deleted before the bot takes it never reaches it. Who else comes and goes is not its business.all: everything said there.
The Queue
Every event a bot is to hear of is noted in its queue in the same transaction that writes the event, so nothing written is ever missing from it. A program takes the queue over the Bot API, and what it confirms goes; confirming a conversation's messages is as far as a bot reads them, so the people it talks with see them read. An update not confirmed within 24 hours of its event goes, and so does one with nothing left to tell.
Buttons
A bot's text message may carry buttons under it, as keyboard: rows of
buttons, each with the text it shows, up to 64 characters on one line, and
either data — 1 to 64 bytes of text the bot is told when somebody presses
it — or a url — an http or https address of up to 2048 characters of
printable ASCII, a name in another script given in punycode, and without a
user before its host — which a client opens once the person agrees. A row has
up to 8 buttons, a keyboard up to 100, taking up to 16 KB as JSON.
Only a bot sends them, in message.send and message.edit; anybody else's are
not_authorized. An edit carries the keyboard the message is to have: none,
when it is left out.
{"id":"poll","type":"message.send","data":{"operation_id":"poll-1","conversation_id":"c_38a2","kind":"text","payload":{"text":"Lunch at noon?"},"keyboard":[[{"text":"Yes","data":"lunch:yes"},{"text":"No","data":"lunch:no"}],[{"text":"Menu","url":"https://example.com/menu"}]]}}
Returned messages carry their keyboard as it is sent. A client shows it under
the message and, when a button with data is pressed, tells the server so,
showing it waits until the press is answered:
{"id":"press-1","type":"button.press","data":{"msg_id":"512","data":"lunch:yes"}}
A press is of a button the message has, in a message the presser sees, of a
bot still in the conversation, and is not_found otherwise. The bot is told of it as button.pressed, in its
account stream: press_id, who it is from, the conversation_id, the
message as the bot sees it, and the button's data:
{"type":"button.pressed","seq":"77","data":{"press_id":"p_6f1c2a9e","from":67890,"conversation_id":"c_38a2","message":{"msg_id":"512","conversation_id":"c_38a2","from":12345,"kind":"text","payload":{"text":"Lunch at noon?"},"time":"2026-10-13T09:00:00Z","revision":1,"reactions":[]},"data":"lunch:yes"}}
The bot answers with button.answer: the press_id, and what the person is
shown, a text of up to 200 characters, alert to be dismissed rather than
shown briefly. That answers the press:
{"id":"answer-1","type":"button.answer","data":{"press_id":"p_6f1c2a9e","text":"Counted","alert":false}}
{"id":"press-1","type":"button.press","ok":true,"data":{"text":"Counted","alert":false}}
A press the bot does not answer within 10 seconds is answered with nothing,
and the client stops waiting; answered later, or by any other bot,
button.answer is not_found. A press is the bot's and the presser's alone:
it goes into no history, and nobody else learns of it. ICQ clients show no
buttons.
Commands
A bot says which commands it takes: lists of a command, 1 to 32 Latin
lower-case letters, digits and underscores written after /, and its
description, up to 256 characters on one line, up to 100 a list. One list is
for everywhere, and others may take its place in direct conversations and in
groups. A bot's profile carries the lists that hold, as commands:
{"commands":{"direct":[{"command":"start","description":"Begin"},{"command":"forecast","description":"The weather where you are"}],"groups":[{"command":"forecast","description":"The weather where you are"}]}}
A client offers them as / is typed, in a conversation with the bot or a
group it is in, from the bot's profile as it fetches it. In a group, a command
chosen is written /command@name, the bot's name, mentioning the bot, so that
a bot hearing only what is addressed to it hears it too. Whoever follows the
bot's profile is told when they change, which they do ten times a minute at
most: more is rate_limited.
The System Bot
The server runs a bot of its own, which makes and keeps people's bots: the
system bot, Bots, by the name bots — shorter than any name a bot may
be given, so that nobody else has it. It is a bot as any other to whoever
writes to it, in a direct conversation, from any client, ICQ's included, and
it is in no group. Its owner is the server; it signs in nowhere, and nobody
manages it.
It is told what to do with commands, a message each — they are its profile's commands — and what a command asks for comes in the messages that follow, a step each, until it is done:
| Command | Steps | Does |
|---|---|---|
/newbot |
the bot's name as people see it (its nick), then its public name |
Makes a bot, and tells its link, ID and token |
/mybots |
— | Lists the sender's bots |
/token |
the bot | Replaces the bot's token, and tells the new one |
/setname |
the bot, then its name | Changes the nick the bot goes by |
/setdescription |
the bot, then the text, or /empty |
Changes what the bot says about itself, its about |
/setuserpic |
the bot, then a picture, or /empty |
Changes or removes the bot's avatar |
/setreads |
the bot, then all or addressed |
Changes what the bot hears of the groups it joins after |
/setjoingroups |
the bot, then enable or disable |
Lets everybody add the bot to groups, or nobody: its group_invites privacy |
/cancel |
— | Gives up the command under way |
/help, /start |
— | Tells what it can do |
A bot is chosen by its public name, with or without @. Where a step has
choices — which bot, which value — they are buttons under what it
asks as well: a press is as the words it stands for, and counts under what it
asked last alone — a press of any button above that is answered that it is
over. A picture is sent as
a photo of up to 10 MB, which the server makes an avatar of as it makes a
preview, aside, telling once it is done — a picture that won't do ends the
command; a server that makes no previews takes a JPEG or PNG of up to 512 KB
as it is. A step
answered wrongly is asked again; another command gives up the one under way,
and so does an hour without an answer, or the server's restart. The system bot
answers at a bot's pace, like any other: past it, a flood goes
unanswered.
Mandarin
The server runs a second account of its own, Mandarin, which tells people
of their accounts, as the chat «Telegram» does there. It has an ID of its own,
1, below where the server's IDs start, so that nobody else ever has it,
and the name mandarin, which no invitation may take. It is a
bot owned by nobody, whom nobody adds to a group; its profile and its
conversation say official as the system bot's do.
It writes to anybody, whatever they let others write to them, unless they
block it, and takes no messages: its conversation has no message.send
among its capabilities, and writing to it returns not_authorized. Over a
transport it is a contact like any other, ID 1, whose
messages arrive and whose buttons do not.
It writes, in the language of the account's session used last that said one (Russian to whoever reads it, English to everybody else):
| When | What |
|---|---|
| A code to sign in is asked for and goes to the app | The code, and the address that asked; marked sign_in_code, it goes to no transport |
| An account is made | A welcome, with a link to the service's news where the server has one |
| A session signs in with a code, or a QR code lets one in | How it got in, its device and address, and buttons that own it or end it |
| A transport's client signs on from an address it did not sign on from for a month | That it did, and from where |
| The account's number changes | That it changed, not to what: transports show it too |
| A transport's password is set, changed or removed | That it was |
| A wrong password is given at a transport five times within an hour | How many, and the last address; once an hour at most |
| A new session takes the place of a CLEMA client's session | Which one ended |
An operator queues a notice (mandarin-server notice <text>) |
The notice, to everybody, within a minute; a server that stops while writing it leaves the people it had taken in hand without it |
A sign-in's notice has two buttons: "It's me" and "End session". A press of "End session" ends that session, if it is still there, and the notice is edited to say it was ended; a press of "It's me" leaves it, and the notice is edited to say it was the account's own. Either way both buttons go.
Bot API
A program drives a bot over HTTP, the Bot API, on the server's own
address: POST /bot/<token>/<method> with JSON parameters, answered
{"ok": true, "result": ...} or {"ok": false, "error": {...}} with the
codes of Error Codes. What a bot does is done as the CLEMA
command a client would make, and fails as that would. Its methods, the updates
and how they are confirmed, webhooks and the pace a bot keeps are described
for bot developers in the Bot API guide.