Skip to content
Hoody.com

Telegram is the chat app hoody-bot speaks today. Bot describes what the kit does once a bot is connected. This page covers the Telegram side: creating the bot, what its token is, the two BotFather settings that decide where it can be used, and which parts of its profile Hoody publishes for you.

A Telegram bot is a Telegram object. You create it in Telegram, you own it there, and Hoody holds nothing but its token. Creating one takes about two minutes and you do it once per bot.


  1. Open Telegram and start a chat with @BotFather, the verified account Telegram runs for creating bots.

  2. Send /newbot.

  3. Send a display name when BotFather asks for one. This is the name people see at the top of the chat, such as Acme Ops. You can change it later.

  4. Send a username. It must be unique across Telegram and end in bot, for example acme_ops_bot. BotFather has no command to change a username afterwards, so pick one you can live with; the display name stays editable.

  5. BotFather replies with the token: a number, a colon, then roughly 35 more characters. Put it straight into a shell variable rather than a file:

    Terminal window
    read -rs BOT_TOKEN # paste the token, press Enter; it is not echoed or saved in history
    export BOT_TOKEN

One command registers it, a second starts polling. Run your container from a chat app covers this step in full, including the HTTP form.

Terminal window
# --token-stdin keeps the token out of the process list and shell history.
printf '%s' "$BOT_TOKEN" | hoody bot create --container "$CONTAINER_ID" \
--channel telegram --token-stdin --label "ops bot"
# A new registration is stopped. Read its id, then start polling.
hoody bot list --container "$CONTAINER_ID"
hoody bot start "$REGISTRATION" --container "$CONTAINER_ID"

The kit checks the token with Telegram before it stores anything, so a wrong token fails here rather than at the first message. hoody bot get <registration> then shows channel_username, which is the bot the registration actually points at. Read it once after registering: it is the difference between a quiet bot and a bot you are messaging under a different username.

The kit fetches updates by long polling and never sets a webhook. If a webhook was set on this bot by something else, starting the registration clears it before the first poll, leaving pending updates in place. Setting a webhook again from outside stops the kit from receiving anything.


Privacy mode is the Telegram setting that decides how much of a group conversation the bot receives. With it on, Telegram limits group delivery to the messages its own privacy-mode rules cover. With it off, it delivers every eligible group message except those sent by other bots, which it never delivers either way. Of the group text that does arrive, the kit handles commands addressed to it, mentions and replies, and ignores the rest.

hoody-bot is written for privacy mode on, and Telegram enables it for every new bot. Confirm rather than assume, since a bot you made earlier for something else may have it off:

  1. Send /setprivacy to BotFather.

  2. Pick the bot.

  3. Choose Enable.

The setting takes effect for groups the bot joins afterwards. For a group it is already in, remove the bot and add it again. Telegram’s own privacy mode description lists the exact message types either way, and it is worth reading before the bot joins a room where people discuss anything you would not want delivered to it.


Two separate things have to be true before a command works in a group: Telegram has to deliver the message, and Hoody has to admit the chat.

  1. Allow or refuse groups at BotFather. /setjoingroups controls whether the bot can be added to a group at all, and Telegram allows it by default. Turn it off if this bot should only ever answer direct messages: nobody can then add it to a room, whatever the kit’s allowlist says.

  2. Add the bot to the group the way you add a member, by its username. It needs no administrator rights to receive commands.

  3. Allowlist the chat in Hoody. Until you do, the kit serves direct messages only, because a read command typed in a group posts one person’s account data into the room.

    Terminal window
    hoody bot policy update "$REGISTRATION" --mode multi \
    --allowlists-chats "$GROUP_CHAT_ID,$YOUR_DM_CHAT_ID"

    The chat list is exhaustive once it is non-empty, so a list naming only the group also stops every direct message. Your own direct-message chat id is your channel user id, which hoody bot logs list records as the actor of everything you send.

When several bots share a group, address the command to yours as /ps@acme_ops_bot. The suffix is matched case-insensitively. The kit answers a command addressed to another bot with silence rather than an error.

Credentials are never accepted in a group. /login there answers with a button that opens a direct message. A pasted token is refused and the bot tries to delete the message; when it cannot, it says so: “I could not delete that message, so it is still there: please delete it yourself and rotate that credential.” Credentials are refused the same way in a forum topic, in a channel, from a guest context and over a business connection. A channel and a topic that is not private share the group refusal.


In a direct message, send /login and choose one of Log in here, Open login page, or Use a token. If you are already logged in, /login offers Switch account or Stay logged in. Switch account asks you to log out first; confirming that ends the session and then shows the three ways in.

Log in here asks for your email and password in the chat, then a two-factor code when the account has one, then a second fresh code for the token mint. The form expires two minutes after it opened, and each reply is deleted after it has been read, as far as the bot can manage it. Open login page sends a link to a form the kit serves from your own container; the link works once and expires after two minutes, and Chat Access describes it in full. Use a token takes a Hoody API token that carries an expiry, pasted into the direct message; the bot deletes that message after reading it, on the same best-effort basis.

/logout ends this chat’s access and tries to delete the session token the login minted. It also ends every browser session held for that chat identity, cancels any form or confirmation left open, and stops that identity’s subscriptions. It answers with one of three sentences: that you were not logged in, that the session token was deleted, or that it could not delete the token, naming the id. For a token you pasted in it says “I have forgotten your token. I never created it, so I cannot delete it.” When anything is left for you to remove, it prints the hoody auth tokens delete command to run.


Some of the bot’s appearance is Hoody’s to publish and some of it stays at BotFather. Setting a piece from both sides means whichever ran last wins, so it is worth knowing which is which.

PieceSet it withNotes
Command list and menuhoody bot commands sync <registration>Publishes the kit’s commands per scope and reads them back. Do not maintain this list with BotFather’s /setcommands: the next sync replaces the scopes it manages
Menu buttonhoody bot commands sync <registration>Set to Telegram’s own default, the commands button. It corrects a button an earlier build or an operator pointed at a web app
Display namehoody bot profile update <registration> --nameSending an empty name clears Hoody’s override and restores the name BotFather holds
Description and short descriptionhoody bot profile update <registration>The description is the text shown before a chat starts; the short description appears in the profile
Default administrator rightshoody bot profile update <registration>What Telegram offers to grant when someone adds the bot to a group as an administrator
Profile photoBotFather /setuserpicHoody never sets it
UsernameFixed at creationNeither side can change it

A Telegram bot cannot open a conversation. Until someone sends it a message or presses Start, it has no way to write to them, and Telegram refuses the attempt. That is a Telegram rule rather than a Hoody one, and it is why event subscriptions only reach people who have already talked to the bot in that chat.


Check the registration is started with hoody bot list, and check hoody bot health for polling. A registration is created stopped, and hoody bot start is what begins polling. A started registration that cannot begin polling after a restart is reported inactive in health and retried with backoff; the two cases below are the ones that are not retried.

last_error_code is conflict when another program is calling getUpdates with the same token, which Telegram allows only one of. The kit stops rather than fighting for it, because two pollers trading a 409 back and forth is an outage that repairs nothing. Stop the other program, or revoke the token and give the other program a bot of its own, then run hoody bot start again.

last_error_code is auth when Telegram refuses the token, which normally means it was revoked at BotFather. Register again with the current token.

Run hoody bot commands sync <registration>. Telegram caches command lists per scope and per language, and the sync reads back what it published, so the result tells you what Telegram actually stored rather than what it accepted.

Work through the three conditions above in order: the bot was added to the group, privacy mode leaves the message deliverable, and the chat is on the allowlist. A refusal by the allowlist is written to the audit log, so hoody bot logs list <registration> tells you which of the three it was.

The bot deletes a credential message as soon as it reads it, and that deletion is best effort. Telegram stored the message the moment you sent it. Use the login page instead of typing credentials into the chat if that matters to you.


Telegram is the only chat app the kit speaks today. Each chat app gets its own page here, covering the same ground: how to create the bot in that app, what its credential is, and which of its settings the kit expects.