# Telegram

**One hlix bot serves every workspace, and a chat joins yours by redeeming a short-lived link code.** Once linked, messages in that chat reach the same chat agent the dashboard talks to, with your workspace's projects, models and tools.
**Why a link code and not a bot of your own:** Telegram has no per-workspace OAuth — a bot token *is* the tenant. A shared bot therefore has no tenancy boundary of its own: without an explicit link step, any stranger who found the bot would be talking to whichever workspace answered first. The code is what proves a chat belongs to you.

## What it does

| Capability | State |
| --- | --- |
| `/link <code>` binds a chat to a workspace | Works |
| Free-text message → chat agent, with its full toolbelt | Works |
| Thread context — recent chat messages sent with the request | Works, capped at 10 messages |
| Typing indicator while the agent works | Works, best-effort |
| Webhook request verification | Works — `TELEGRAM_WEBHOOK_SECRET_TOKEN`, checked by the adapter |
| A message from an unlinked chat | Politely refused, naming the link flow |
| Mapping a Telegram account to a hlix user | **Not implemented.** The chat's workspace membership is the whole authorization |

Every message is recorded in the [audit log](/concepts/audit/) as `integration.channel.dispatched`, with the Telegram user id and name on the row — so the trail names a human even though no hlix session exists for them.

## Prerequisites

- A hlix workspace, and agency `owner` or `admin` — minting a link code is workspace administration
- The deployment configured with the hlix bot (operator work, below)

## Link a chat

1. **Generate a code** in the dashboard under **Integrations → Telegram**, or directly:

   ```bash
   curl -X POST https://server.hlix.ai/v1/api/integrations/telegram/link-code \
     -H "X-Organization-Id: $HLIX_ORG" \
     -H "Authorization: Bearer $HLIX_TOKEN"
   ```

   ```json
   {
     "code": "K7M2PQ9XTVA3JHNR4B0C",
     "expiresAt": "2026-08-09T12:15:00.000Z",
     "command": "/link K7M2PQ9XTVA3JHNR4B0C",
     "botUsername": "hlix_bot"
   }
   ```

   The response is the **only** copy of the code that will ever exist — the database stores a SHA-256 of it, not the code.

2. **Send it to the bot**, in a direct message or in a group the bot has joined:

   ```text
   /link K7M2PQ9XTVA3JHNR4B0C
   ```

   Dashes, spaces and lower case are all accepted.

3. **Confirm.** The bot replies:

   ```text
   This chat is now linked to your hlix workspace. Ask me anything — I can list projects, create tasks and run cycles.
   ```

4. **Talk to it.** Anything that is not a command goes to the chat agent.
**A code is single-use and expires in 15 minutes:** Redeeming spends it. A second attempt with the same code fails, whoever sends it. Generate a fresh one rather than reusing an old message.

## Who can act through a linked chat

Everyone in that chat, with the workspace's full agent toolbelt — which can create tasks and execute cycles. hlix does not map Telegram accounts to hlix users, so the chat's membership is the access boundary, exactly as the chat's membership is on Telegram's side.
**Treat a linked group like a room with the keys in it:** Adding someone to a linked group grants them the agent. Revoke the installation before the membership of a linked chat changes in a way you would not grant in the dashboard.

## Operator configuration

This part is deployment-wide, not per workspace.

1. **Create the bot** with Telegram's [@BotFather](https://t.me/botfather) and copy its token.

2. **Set the environment**, all three:

   ```text
   TELEGRAM_BOT_TOKEN            # from @BotFather
   TELEGRAM_WEBHOOK_SECRET_TOKEN # any high-entropy string you choose
   TELEGRAM_BOT_USERNAME         # e.g. hlix_bot, so /link@hlix_bot resolves
   ```

   Without `TELEGRAM_WEBHOOK_SECRET_TOKEN` the platform reports Telegram as **not configured** and refuses the webhook. That is deliberate: the adapter accepts every POST when no secret token is set, and an unverified endpoint is one anyone can deliver updates to.

3. **Register the webhook with Telegram**, passing the same secret:

   ```bash
   curl -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/setWebhook" \
     -d "url=https://server.hlix.ai/webhooks/channels/telegram" \
     -d "secret_token=$TELEGRAM_WEBHOOK_SECRET_TOKEN"
   ```

4. **Verify** by sending `/link` with no code. The bot should answer with the instructions, which proves both delivery and verification.

## Security

Every inbound request carries `X-Telegram-Bot-Api-Secret-Token`, compared in constant time against `TELEGRAM_WEBHOOK_SECRET_TOKEN`; a mismatch is a `401` before anything else happens. The workspace is derived server-side from the chat id, never from anything in the request body — an unrecognised chat resolves to no workspace and is refused rather than defaulted.

## If it does not respond

- **`This chat isn't linked to a hlix workspace yet.`** — the chat has no live installation. Generate a code and send `/link <code>`.
- **`That link code is not valid.`** — unknown, already spent, or expired. All three give the same answer on purpose, so redemption cannot be used to discover which codes exist.
- **`403` — ``admin only``** on the link-code endpoint. Minting is `owner`/`admin` work.
- **`503` — ``Telegram is not configured on this server``** — the deployment is missing `TELEGRAM_BOT_TOKEN` or `TELEGRAM_WEBHOOK_SECRET_TOKEN`. An operator fix, not a user one.
- **`401 Invalid secret token`** — Telegram is sending a different secret than the backend holds. Re-run `setWebhook` with the value currently in the environment.
- **No reply at all** — Telegram is not delivering. Check `getWebhookInfo` for the registered URL and its `last_error_message`.
**Earlier versions of this page were describing a stub:** Until this release, `/webhooks/telegram` verified nothing and its message handler only wrote a log line; the `/projects`, `/new` and `/status` commands documented before that were never registered at all. That endpoint is gone. The route is now `/webhooks/channels/telegram`.

## Next steps

[Slack](/integrations/slack/)
  [Linear](/integrations/linear/)
  [CLI reference](/reference/cli/)
  [Integrations](/integrations/)