> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sesameterminal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Runbook: Telegram notifications

# Runbook: Telegram notifications

Use this runbook to connect sesame to a Telegram bot. Then notifications reach your phone when
no browser tab is open. In the app, **Settings > Notifications** links to this page while
Telegram is not set up. The words this page uses are in the deploy guide's
[Words used in these pages](../guides/deploy/index.md#words-used-in-these-pages).

The bot only sends messages. It cannot read your messages, and it cannot place orders or move
funds. What each notification says is in
[notifications.md](../design/screens/notifications.md#copy-per-notification-kind).

Official Telegram documentation: [https://core.telegram.org/bots/tutorial](https://core.telegram.org/bots/tutorial) and
[https://core.telegram.org/bots/api](https://core.telegram.org/bots/api).

## 1. Create a bot with @BotFather

Do these steps in the Telegram app, on your phone or your computer.

1. Open a chat with **@BotFather**. Make sure that the account has a blue tick and that the
   user name is exactly `BotFather`.
2. Send `/newbot`.
3. Send a display name for the bot, for example `sesame`.
4. Send a user name for the bot. It must end in `bot` and no other bot can have it, for
   example `my_sesame_alerts_bot`.
5. Copy the token from BotFather's reply. It has this shape:

   ```text theme={null}
   0000000000:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   ```

   The token is digits, a colon, then 30 to 100 letters, digits, `_` and `-`.

WARNING: Keep the token secret, like a password. A person with the token can send messages as
your bot and read the messages sent to it. Do not paste it into a chat, an issue, a
screenshot, a commit or an AI agent session.

## 2. Get your chat id

The chat id tells the bot where to send. For a private chat with the bot, the chat id is your
own Telegram user id, a positive number.

1. In Telegram, search for your bot's user name and open a chat with it.

2. Press **Start**, or send any message to the bot. The bot cannot send to you until you do
   this.

3. Read the bot's updates once. Use one of the three methods below. Each method keeps the
   token out of your history.

   **Method A: a browser on your computer**

   1. Open a private browser window.
   2. Go to `https://api.telegram.org/bot<token>/getUpdates`. Replace `<token>` with your
      token. Keep the `bot` before it.
   3. Close the private window after you copy the chat id.

   **Method B: a terminal on your computer (Linux, or Git Bash on Windows)**

   1. Type this command, then paste the token and press Enter. The token does not show:

      ```bash theme={null}
      read -rs TOKEN
      ```

   2. Get the updates:

      ```bash theme={null}
      curl -s "https://api.telegram.org/bot${TOKEN}/getUpdates"
      ```

   3. Remove the token from the shell:

      ```bash theme={null}
      unset TOKEN
      ```

   **Method C: PowerShell on Windows**

   1. Type this command, then paste the token and press Enter:

      ```powershell theme={null}
      $s = Read-Host -AsSecureString "Token"
      ```

   2. Get the updates:

      ```powershell theme={null}
      $t = [Runtime.InteropServices.Marshal]::PtrToStringAuto([Runtime.InteropServices.Marshal]::SecureStringToBSTR($s))
      Invoke-RestMethod "https://api.telegram.org/bot$t/getUpdates" | ConvertTo-Json -Depth 6
      ```

   3. Remove the token from the shell:

      ```powershell theme={null}
      Remove-Variable s, t
      ```

4. In the reply, find `"chat":{"id":` in your message. The number after it is the chat id:

   ```json theme={null}
   {"ok":true,"result":[{"update_id":1,"message":{"message_id":1,
     "from":{"id":111111111,...},"chat":{"id":111111111,"type":"private",...},
     "text":"/start"}}]}
   ```

5. Write down the chat id.

If the reply is `"result":[]`, Telegram has no updates for the bot. Send the bot another
message and do step 3 again. Telegram keeps updates for 24 hours.

To send to a group or a channel:

* A group or channel chat id is negative, for example `-1001111111111`. Keep the minus sign.
* For a channel, add the bot as an admin of the channel. Then post in the channel and read the
  id from `"channel_post"` in the reply.
* Use the number, not the `@channelname`. The app refuses a name, because another person can
  take over a public name.

The app itself never reads updates. You need `getUpdates` only this once.

## 3. Add the token and chat id to the settings file

1. On the server, open the settings file:

   ```sh theme={null}
   sudoedit /opt/sesame/sesame.env
   ```

2. Add these two lines, with your token and your chat id:

   ```dotenv theme={null}
   TELEGRAM_BOT_TOKEN=0000000000:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
   TELEGRAM_CHAT_ID=111111111
   ```

3. Save the file and close the editor.

Set both lines, or neither. In development, put the same two lines in the `.env` file in the
repository root. Each setting is in the
[configuration reference](../guides/configuration.md#settings-you-may-want-to-change).

The app checks the two values when it starts. If one is wrong, the app does not start and the
log shows one of these messages. The messages never show the value.

| Message in the log | What to do |
| - | - |
| `TELEGRAM_CHAT_ID: empty while TELEGRAM_BOT_TOKEN is set; set both or neither` | Add the chat id, or remove both lines |
| `TELEGRAM_BOT_TOKEN: empty while TELEGRAM_CHAT_ID is set; set both or neither` | Add the token, or remove both lines |
| `TELEGRAM_BOT_TOKEN: not a Bot API token (digits, a colon, then the secret)` | Copy the token from @BotFather again |
| `TELEGRAM_CHAT_ID: must be a numeric chat id, negative for a group` | Use the number from step 2, not a name |

## 4. Restart and send a test

1. On your computer, restart the app so that it reads the new settings:

   ```sh theme={null}
   task deploy:start
   ```

   The command ends with a table that lists the `sesame` and `caddy` services. In
   development, stop `task dev` and start it again.

2. In Telegram, look for the startup message from the bot:

   ```text theme={null}
   Server started
   Audit log verified · head 293abdeda8eceec84764e7b02c0549f87cc017bf971622a68649c9836af65d60 at seq 1284
   ```

   The second line is the newest entry of the order audit log. Compare it with the previous
   startup message. The `seq` number never goes down. If the `seq` is the same, the hash is
   the same. The second line can also be one of these:

   | Second line | Meaning |
   | - | - |
   | `Audit log does not verify at seq <n>` | A row of the audit log was changed or removed. Follow the `task audit-verify` row of the [incident runbook](incident.md#5-other-problems) |
   | `Audit log not checked · read failed` | The app could not read the audit log at start |
   | `Audit log empty` | The app has no orders yet |

   A third line `Schema repaired · <names>` shows when the start repaired parts of the
   database.

3. In the app, open **Settings > Notifications**. Make sure that the `Not configured ·
   Telegram runbook` line is gone and that the **Telegram** column is not greyed out.

4. Click **Send test**. Telegram receives this message:

   ```text theme={null}
   Test notification
   Sent from Settings
   ```

   The app also shows the test as a toast and plays the sound if the volume is above 0.
   The test goes to Telegram even when every box in the **Telegram** column is clear. You
   can send one test each 10 seconds.

5. In the **Telegram** column, select the notifications you want on Telegram.

These notifications go to Telegram by default:

* Alerts
* Fills
* Orders cancelled at start
* Feed disconnected
* Activity outside this app
* Credentials unavailable
* Cancel on shutdown failed
* Logins refused for new devices
* Combo fills
* Combos not filled

**Activity outside this app** and **Credentials unavailable** always go to Telegram and to the
app. Their boxes are selected and you cannot clear them. Their tooltip is
`Always on for safety`.

## 5. When the test says `Not sent · Telegram refused the message`

The app shows this line under **Send test** when Telegram refused the test or did not answer.
The toast and the sound still work. Only Telegram failed.

1. Read the app's log on your computer:

   ```sh theme={null}
   task deploy:logs
   ```

2. Find the line `test notification failed`. Its `error` field holds Telegram's status and
   reply. It never holds the token.

3. Find the reply in the table below and do the action.

4. Click **Send test** again.

| Telegram's reply in the log | Cause | What to do |
| - | - | - |
| `status 401` and `Unauthorized` | The token is wrong, or you revoked it | Copy the current token from @BotFather into `TELEGRAM_BOT_TOKEN`. Then restart (step 4) |
| `status 400` and `chat not found` | The chat id is wrong, or you did not press **Start** in the bot's chat | Do step 2 again and correct `TELEGRAM_CHAT_ID`. Then restart |
| `status 403` and `bot was blocked by the user` | You blocked the bot or deleted its chat | Unblock the bot and press **Start** again |
| `status 403` and `bot is not a member of the channel chat` | The bot is not an admin of the channel | Add the bot to the channel as an admin |
| `status 429` | Telegram limits the bot and asks for a wait of more than 60 seconds | Wait, then send the test again |
| `context deadline exceeded`, or no status | Telegram did not answer in 10 seconds | Make sure that the server can connect to `api.telegram.org`. The app does not send the test again |
| `telegram send limit reached` | The app sent its maximum of Telegram messages in the last minute. Telegram did not get the test | Wait one minute |

Other lines under **Send test**:

| Line | Meaning |
| - | - |
| `Not sent · one test per 10 s` | You clicked **Send test** less than 10 seconds after the last test |
| `Not sent · no response from server` | The browser could not reach the app |

The app never sends a failed test again. A duplicate message is worse than no message.

## 6. Rate limits and summaries

* The app sends at most 20 Telegram messages a minute.

* Ordinary notifications can use 15 of the 20. The other 5 are for these urgent
  notifications: **Activity outside this app**, **Credentials unavailable**,
  **Feed disconnected**, a failed fill, **Cancel on shutdown failed** and **Logins refused for
  new devices**.

* Urgent notifications go first and one at a time. **Activity outside this app** and
  **Credentials unavailable** go before the others. The app never puts an urgent notification
  in a summary.

* A price or spread alert that repeats sends at most one message a minute. A score alert
  sends a message at each score change.

* When ordinary messages must wait, the app sends them together as one summary when a slot
  is free. The summary counts the messages by title, the largest count first:

  ```text theme={null}
  12 more notifications
  8 Order filled · 4 Price alert
  ```

* If the waiting list was full, the first number also counts the messages that the app
  dropped. The app logs `telegram messages dropped`.

* If Telegram answers `429`, the app waits the time Telegram asks for and sends the message
  once more. If that time is more than 60 seconds, the app does not send it again.

* After any other failure, a timeout too, the app does not send the message again. It logs
  `telegram send failed`.

* The app keeps every notification in its history for 30 days, with its full text. Open the
  **Notifications** tab of the **Alerts** page to see it.

## 7. What the bot can and cannot do

| The bot | Status |
| - | - |
| Sends plain text to one chat, with link previews off | Allowed |
| Sends market titles, outcomes, prices, sizes, scores and dollar limits | Allowed |
| Sends a message of more than 4096 characters | Not allowed. The app cuts it and ends it with `…` |
| Sends control, line-break or text-direction characters from venue text | Not allowed. The app changes each one to a space |
| Sends keys, credentials or account addresses | Not allowed. No message contains them |
| Reads messages, or answers commands | Not allowed. The app sets no webhook, so a message to the bot has no effect on the app |
| Places, cancels or changes orders, or moves funds | Not allowed. The app has no code for this |

## 8. Revoke or replace the token

Revoke the token if it may have leaked, for example in a screenshot or a shell history.
Revoke it also when you do not need the bot any more.

1. In @BotFather, send `/revoke`.
2. Choose the bot and confirm. The old token stops at once. BotFather shows a new token.
3. Do one of these:
   * To keep Telegram, put the new token in `TELEGRAM_BOT_TOKEN` (step 3).
   * To stop Telegram, remove both `TELEGRAM_BOT_TOKEN` and `TELEGRAM_CHAT_ID` (step 3).
4. Restart the app (step 4).
5. To remove the bot completely, send `/deletebot` to @BotFather.

Until the app restarts with a token that works, each Telegram message fails with status 401. The
app logs `telegram send failed`. The other channels continue to work.

A leaked token lets a person send messages as your bot and read the messages sent to it. It
gives no access to the app or to the Polymarket account. For a leaked Session Key or login
password, use the [incident runbook](incident.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.