# Telegram Setup

This page covers constructing the `core/telegram` bot, its connection options, and the `Input` your handler receives.

## Constructor and options

```go
bot, err := telegram.New(token,
    telegram.WithPollTimeout(50*time.Second),
    telegram.WithHTTPClient(&http.Client{Timeout: 70 * time.Second}),
)
```

`New` returns `token is required` for an empty token and wraps SDK errors as `Bot.New: ...`. The SDK constructor calls `getMe` once with a 5-second timeout, so an invalid token or an unreachable Telegram API already fails here as `Bot.New: error call getMe, ...`. No polling starts until `Start`.

| Option | Sets | When neither option is passed |
|---|---|---|
| `WithPollTimeout(d time.Duration)` | The long-poll `timeout` sent to `getUpdates` | SDK defaults apply |
| `WithHTTPClient(c *http.Client)` | The client used for polling and uploads | SDK defaults apply |

When only one option is passed, the other is filled in: the poll timeout defaults to 1 minute, and the client defaults to `&http.Client{Timeout: pollTimeout}`.

Set `client.Timeout` longer than the poll timeout. The same client serves long polling and multipart uploads; if the client timeout is equal to or shorter than the poll timeout, an idle poll is cancelled before Telegram answers and surfaces as `context deadline exceeded`. Large uploads also need the extra headroom.

## Start and webhooks

`Start(ctx)` calls `GetMe` (a failure is returned), then `GetWebhookInfo`. If the bot has a webhook URL set, `DeleteWebhook` runs with `DropPendingUpdates: false`, because Telegram refuses long polling while a webhook is active. Failures in these two calls are logged and do not stop `Start`.

Runtime errors from the polling loop are logged. When Telegram answers with HTTP 429 (too many requests) and a `retry_after`, the error handler sleeps for that many seconds before polling continues.

## Input

| Field | Type | Content |
|---|---|---|
| `ChatID` | `int64` | Chat the event came from |
| `ChatName` | `string` | Group/channel `Title`, else `Username`, else `FirstName LastName` (private chats), else `""` |
| `MessageID` | `int` | The user's message; for select callbacks, the bot's prompt message |
| `UserID` / `Username` | `int64` / `string` | Sender (`From`); zero values when absent |
| `Text` / `Caption` | `string` | Message text, or caption of a media message |
| `Photo` | `[]models.PhotoSize` | All sizes of a photo; the last entry is usually the largest |
| `Document` | `*models.Document` | Attached document, if any |
| `CallbackData` | `string` | Item tapped in a `SendSelect` keyboard |
| `CallbackPicks` | `[]string` | Items chosen in a `SendMultiSelect` keyboard |
| `Raw` | `*models.Update` | The full SDK update, for fields not copied above |

`CallbackData` and `CallbackPicks` are mutually exclusive. To read a `SendInput` answer, compare `in.Raw.Message.ReplyToMessage.ID` with the prompt's ID.

## Related pages

- [Telegram Messages](/telegram-messages)
- [Telegram Interactions](/telegram-interactions)
- [Saving Media](/media-save)
- [Telegram API](/api-reference-telegram)
