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.`)
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)
}