Skip to main content

Messages and Replies

Sending messages is the core of any bot. This page covers text, media, formatting, replies, and editing. For every variant and parameter, see Statement Reference → Messaging.

Sending text

send.text("Hello, world!")

Use a backtick template to interpolate variables:

send.text(`Hi ${user.first_name}, you have ${user.visits} visits.`)
tip

Inside ${...}, use simple references only (user.first_name, flow.total). Compute anything complex in a set { } block first, then reference the result. See Expressions.

Formatting with parse_mode

Telegram supports Markdown and HTML. Pass parse_mode:

send.text("*Bold* and _italic_ and `code`.", parse_mode: "Markdown")

send.text("<b>Bold</b> and <i>italic</i>.", parse_mode: "HTML")

Sending media

send.photo(file: "https://example.com/cat.jpg", caption: "A cat 🐱")
send.video(file: "https://example.com/clip.mp4", caption: "Watch this")
send.document(file: "https://example.com/report.pdf", caption: "Q3 report")

Media also accepts captions with parse_mode. The full list — audio, voice, animation, location, venue, contact, poll, dice, sticker, media groups, and more — is in Statement Reference → Messaging.

Replying to a message

send.text accepts an optional reply_to to attach your message as a Telegram reply:

send.text("Got it!", reply_to: message.message_id)

Sending messages with menus

The reply_markup parameter attaches an interactive keyboard to any message. The recommended approach is a named menu:

menu mainMenu {
text "🎮 Play" -> startPlay()
text "📊 Stats" -> showStats()
}

flow start on command "/start" {
send.text("Welcome!", reply_markup: mainMenu)
}

Named menus re-render automatically when their state changes. See Keyboards & menus for the full reference.

Editing a message

To update a message you already sent, use edit.text. Inside a callback flow it automatically targets the message the button was attached to — no message id needed:

flow refresh on callback "refresh" {
edit.text(message: callback.message, text: "✅ Refreshed!", reply_markup: mainMenu)
}

You can also edit just the caption or the keyboard:

edit.caption(message: callback.message, caption: "New caption")
edit.reply_markup(message: callback.message, reply_markup: mainMenu)

Deleting a message

delete(message: callback.message)

Callbacks answer themselves

When a flow is triggered by a button tap, Botgami automatically clears Telegram's loading spinner at the end of the flow — you don't need to add an answer step. If you want to show a toast or alert, use send.answer_callback:

flow buy on callback "buy" {
send.answer_callback(text: "Added to cart!")
send.text("🛒 1 item in your cart.")
}

Sending to another chat

By default messages go to the current user/chat. Pass chat_id to target a specific chat — required in scheduled and webhook flows, which have no chat in scope:

flow daily on schedule "0 9 * * *" {
send.text("Daily digest 📰", chat_id: shared.group_chat_id)
}

Next