Tgbotrs
A strongly-typed, async Rust client for the Telegram Bot API, generated from the official spec.
Install / Use
/learn @ankit-chaubey/TgbotrsREADME
<br/>All 285 types and 165 methods of the Telegram Bot API —
strongly typed, fully async, automatically kept in sync with every official release.
📦 Install · 🚀 Quick Start · 📖 Examples · 🔧 API Reference · 🔄 Auto-Codegen · 📚 docs.rs
</div>✨ Features
<table> <tr> <td width="50%">🤖 Complete API Coverage
- All 285 types — structs, enums, markers
- All 165 methods — fully async
- All 21 union types as Rust enums
- 100 optional params structs with builder pattern
🔄 Auto-Generated & Always Fresh
- Spec sourced from tgapis/x — auto-updated every 6 hours
- Pipeline dispatches regeneration on every new API version
- PR auto-opened with full semantic diff on every change
- Zero manual work to stay up-to-date
🦀 Idiomatic Rust
- Fully
async/awaitwith Tokio Into<ChatId>— acceptsi64or"@username"Into<String>on all text paramsOption<T>for all optional fieldsBox<T>to break recursive type cycles
🛡️ Fully Type-Safe
ChatId— integer or username, no stringly typingInputFile— file_id / URL / raw bytesReplyMarkup— unified enum for all 4 keyboard typesInputMedia— typed enum for media groups- Compile-time guarantees on every API call
📡 Flexible HTTP Layer
- Custom API server support (local Bot API)
- Multipart file uploads built-in
- Configurable timeout
- Flood-wait aware error handling
reqwestbackend
📬 Built-in Polling
- Long-polling dispatcher included
- Spawns a Tokio task per update
- Configurable timeout, limit, allowed_updates
- Clean concurrent update processing
📦 Installation
Add to your Cargo.toml:
[package]
name = "mybot"
version = "0.1.0"
edition = "2021"
[dependencies]
tgbotrs = ">=0.1.5"
tokio = { version = "1", features = ["full"] }
Requirements: Rust
1.75+· Tokio async runtime
🚀 Quick Start
use tgbotrs::Bot;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let bot = Bot::new("YOUR_BOT_TOKEN").await?;
println!("✅ Running as @{}", bot.me.username.as_deref().unwrap_or("unknown"));
println!(" ID: {}", bot.me.id);
// chat_id accepts i64, negative group IDs, or "@username"
let msg = bot.send_message(123456789i64, "Hello from tgbotrs! 🦀", None).await?;
println!("📨 Sent message #{}", msg.message_id);
Ok(())
}
📖 Examples
🔁 Echo Bot — Long Polling
The simplest possible bot. Receives every message and echoes it back.
use tgbotrs::{Bot, Poller, UpdateHandler};
#[tokio::main]
async fn main() {
let bot = Bot::new(std::env::var("BOT_TOKEN").unwrap())
.await
.expect("Invalid token");
println!("🤖 @{} is running...", bot.me.username.as_deref().unwrap_or(""));
let handler: UpdateHandler = Box::new(|bot, update| {
Box::pin(async move {
let Some(msg) = update.message else { return };
let Some(text) = msg.text else { return };
let _ = bot.send_message(msg.chat.id, text, None).await;
})
});
Poller::new(bot, handler)
.timeout(30)
.limit(100)
.start()
.await
.unwrap();
}
💬 Formatted Messages
Send HTML or MarkdownV2 formatted messages with optional settings.
use tgbotrs::gen_methods::SendMessageParams;
let params = SendMessageParams::new()
.parse_mode("HTML".to_string())
.disable_notification(true);
bot.send_message(
"@mychannel",
"<b>Bold</b> · <i>Italic</i> · <code>code</code> · <a href='https://example.com'>Link</a>",
Some(params),
).await?;
🎹 Inline Keyboards
Buttons embedded inside messages. Perfect for interactive menus.
use tgbotrs::{ReplyMarkup, gen_methods::SendMessageParams};
use tgbotrs::types::{InlineKeyboardButton, InlineKeyboardMarkup};
let keyboard = InlineKeyboardMarkup {
inline_keyboard: vec![
vec![
InlineKeyboardButton {
text: "✅ Accept".into(),
callback_data: Some("accept".into()),
..Default::default()
},
InlineKeyboardButton {
text: "❌ Decline".into(),
callback_data: Some("decline".into()),
..Default::default()
},
],
vec![
InlineKeyboardButton {
text: "🌐 Visit Website".into(),
url: Some("https://ankitchaubey.in".into()),
..Default::default()
},
],
],
};
let params = SendMessageParams::new()
.parse_mode("HTML".to_string())
.reply_markup(ReplyMarkup::InlineKeyboard(keyboard));
bot.send_message(chat_id, "<b>Make a choice:</b>", Some(params)).await?;
⚡ Callback Queries
Handle button taps from inline keyboards. Always acknowledge with answer_callback_query.
use tgbotrs::gen_methods::{AnswerCallbackQueryParams, EditMessageTextParams};
use tgbotrs::types::MaybeInaccessibleMessage;
let handler: UpdateHandler = Box::new(|bot, update| {
Box::pin(async move {
let Some(cq) = update.callback_query else { return };
let data = cq.data.as_deref().unwrap_or("");
// Always acknowledge — dismisses the loading spinner
let _ = bot
.answer_callback_query(
cq.id.clone(),
Some(
AnswerCallbackQueryParams::new()
.text(format!("You chose: {}", data))
.show_alert(false),
),
)
.await;
// Edit the original message in-place
if let Some(msg) = &cq.message {
if let MaybeInaccessibleMessage::Message(m) = msg.as_ref() {
let edit_params = EditMessageTextParams::new()
.chat_id(m.chat.id)
.message_id(m.message_id)
.parse_mode("HTML".to_string());
let _ = bot
.edit_message_text(
format!("✅ You selected: <b>{}</b>", data),
Some(edit_params),
)
.await;
}
}
})
});
⌨️ Reply Keyboards
Custom keyboard shown at the bottom of the screen. Great for persistent menu buttons.
use tgbotrs::{ReplyMarkup, gen_methods::SendMessageParams};
use tgbotrs::types::{KeyboardButton, ReplyKeyboardMarkup};
let keyboard = ReplyKeyboardMarkup {
keyboard: vec![
vec![
KeyboardButton {
text: "📍 Share Location".into(),
request_location: Some(true),
..Default::default()
},
KeyboardButton {
text: "📱 Share Contact".into(),
request_contact: Some(true),
..Default::default()
},
],
vec![
KeyboardButton { text: "🏠 Home".into(), ..Default::default() },
KeyboardButton { text: "⚙️ Settings".into(), ..Default::default() },
],
],
resize_keyboard: Some(true),
one_time_keyboard: Some(true),
..Default::default()
};
let params = SendMessageParams::new()
.reply_markup(ReplyMarkup::ReplyKeyboard(keyboard));
bot.send_message(chat_id, "Use the keyboard below 👇", Some(params)).await?;
📸 Send Photos & Files
Send files by file_id, URL, or raw bytes from disk.
use tgbotrs::{InputFile, gen_methods::SendPhotoParams};
let params = SendPhotoParams::new()
.caption("Look at this! 📷".to_string())
.parse_mode("HTML".to_string());
// Fastest — already on Telegram's servers
bot.send_photo(chat_id, "AgACAgIAAxkBAAI...", Some(params.clone())).await?;
// Let Telegram download from a U
Related Skills
next
A beautifully designed, floating Pomodoro timer that respects your workspace.
product-manager-skills
40PM skill for Claude Code, Codex, Cursor, and Windsurf: diagnose SaaS metrics, critique PRDs, plan roadmaps, run discovery, and coach PM career transitions.
devplan-mcp-server
3MCP server for generating development plans, project roadmaps, and task breakdowns for Claude Code. Turn project ideas into paint-by-numbers implementation plans.
