Building UI

Callback queries

A callback query is what arrives at your bot when a user taps an inline-keyboard button with a Data payload. You answer it within 15 seconds; if you do not, the spinner on the button stays forever.

The flow

  1. Bot sends a message with inline-keyboard buttons that carry data payloads.
  2. User taps a button.
  3. Telegram delivers a CallbackQuery to the bot with the data.
  4. Bot calls Answer — either a silent ack or a popup / alert.
  5. Optionally the bot edits the original message to reflect the new state.

Registering a handler

The callback handler signature is func(*CallbackQuery) error. Wire it through On or directly:

client.On("callback:vote:*", onVote)
client.AddCallbackHandler("vote:*", onVote)
client.On("callback:vote:*", onVote)
client.AddCallbackHandler("vote:*", onVote)

Data buttons

kbd := telegram.NewKeyboard().AddRow(
	telegram.Button.Data("Vote ↑", "vote:up"),
	telegram.Button.Data("Vote ↓", "vote:dn"),
).Build()

client.SendMessage(peerID, "Was it useful?", &telegram.SendOptions{
	ReplyMarkup: kbd,
})

client.On("callback:vote:*", func(q *telegram.CallbackQuery) error {
	switch string(q.Data) {
	case "vote:up":
		_, err := q.Answer("Thanks!")
		return err
	case "vote:dn":
		_, err := q.Answer("Noted.")
		return err
	}
	return nil
})
kbd := telegram.NewKeyboard().AddRow(
	telegram.Button.Data("Vote ↑", "vote:up"),
	telegram.Button.Data("Vote ↓", "vote:dn"),
).Build()

client.SendMessage(peerID, "Was it useful?", &telegram.SendOptions{
	ReplyMarkup: kbd,
})

client.On("callback:vote:*", func(q *telegram.CallbackQuery) error {
	switch string(q.Data) {
	case "vote:up":
		_, err := q.Answer("Thanks!")
		return err
	case "vote:dn":
		_, err := q.Answer("Noted.")
		return err
	}
	return nil
})

Data payloads are arbitrary bytes up to 64 bytes long. Convention is a colon-separated verb and arguments (vote:up, delete:42, page:next:5). On the receiving side, q.Data is a []byte — cast with string(q.Data) when you want to switch on it.

Answering the query

The signature is q.Answer(text, ...opts). Empty text is a silent ack:

_, _ = q.Answer("")
_, _ = q.Answer("")

Non-empty text shows as a toast (top of screen, a few seconds):

_, _ = q.Answer("Thanks!")
_, _ = q.Answer("Thanks!")

Modal alert (sticks until dismissed):

_, err := q.Answer("That permission has been revoked.",
	&telegram.CallbackOptions{Alert: true})
_, err := q.Answer("That permission has been revoked.",
	&telegram.CallbackOptions{Alert: true})

CallbackOptions fields:

Alert bool
Show as a modal alert instead of a top-of-screen toast.
CacheTime int32
Seconds the client should cache this answer for. Subsequent taps inside the cache window show the same answer without round-tripping to the bot.
URL string
For game bots: the URL to open instead of (or in addition to) the answer text.

Edit and respond

Most callback handlers also update the message in place:

_, err := q.Edit("voted!", &telegram.SendOptions{
	ReplyMarkup: telegram.NewKeyboard().AddRow(
		telegram.Button.Data("Undo", "vote:undo"),
	).Build(),
})
_, err := q.Edit("voted!", &telegram.SendOptions{
	ReplyMarkup: telegram.NewKeyboard().AddRow(
		telegram.Button.Data("Undo", "vote:undo"),
	).Build(),
})

q.Edit edits the message the button was attached to, taking the same SendOptions you would pass to EditMessage. q.Respond sends a new message in the same chat:

_, err := q.Respond("Here is more detail:", &telegram.SendOptions{
	ReplyID: q.MessageID,
})
_, err := q.Respond("Here is more detail:", &telegram.SendOptions{
	ReplyID: q.MessageID,
})

Other helpers on *CallbackQuery: GetMessage(), GetSender(), GetChat(), GetChannel(), RespondMedia(media, opts), Conv(timeout) to start a conversation in the chat the button lived on.

URL, login, pay buttons

Buttons that open a URL (Button.URL), request login (Button.Auth), or trigger payment (Button.Buy) do not produce callback queries — the client handles them directly. WebView buttons (Button.WebView) similarly do not show up here; the bot receives a service message containing the data the Web App submitted, handled via the action event on the dispatcher.