A feature-filled Telegram bot API library written in Lua, created by Matt. Supports Bot API 9.4 with full coverage of all available methods.
Requires Lua 5.1+ and LuaRocks:
luarocks install telegram-bot-lua
local api = require('telegram-bot-lua').configure('YOUR_BOT_TOKEN')
function api.on_message(message)
if message.text then
api.send_message(message.chat.id, 'You said: ' .. message.text)
end
end
api.run({ timeout = 60 })api.run() is async by default: each update gets its own coroutine and all API calls are non-blocking.
- Full Bot API 9.4 coverage (messages, media, payments, stickers, forums, games, gifts, stories, and more)
- Async-first architecture via copas: concurrent updates, parallel API calls, background tasks
- Built-in adapters: SQLite, PostgreSQL, Redis, OpenAI, Anthropic (Claude), and SMTP email
- Lua 5.1 - 5.5 support with automatic polyfills for bitwise operations and string.pack
- Clean opts-table pattern for all API methods
- Chainable keyboard and inline result builders
- Text formatting helpers for HTML, Markdown, and MarkdownV2
- Command parsing, pagination, deep links, and callback data encoding
- Member status helpers and chat permission checks
- Legacy v2 compatibility layer with deprecation warnings
| Document | Description |
|---|---|
| Getting Started | Installation, configuration, and first bot |
| Update Handlers | All available update handler functions |
| API Methods | Complete method reference |
| Builders | Keyboards, inline results, and type constructors |
| Utilities | Formatting, command parsing, pagination, and tools |
| Async / Concurrency | Concurrent updates, parallel calls, background tasks |
| Adapters | Database, Redis, LLM, and email integrations |
| Migration from v2 | Breaking changes and upgrade guide |
local api = require('telegram-bot-lua').configure(os.getenv('BOT_TOKEN'))
-- Connect adapters
local db = api.db.connect({ driver = 'sqlite', path = 'bot.db' })
db:execute('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)')
local llm = api.llm.new({
provider = 'anthropic',
api_key = os.getenv('ANTHROPIC_API_KEY'),
model = 'claude-sonnet-4-5-20250929',
})
function api.on_message(message)
if not message.text then return end
local cmd = api.extract_command(message)
if cmd and cmd.command == 'start' then
local name = api.fmt.bold(api.get_name(message.from))
db:execute('INSERT OR IGNORE INTO users VALUES (?, ?)', {message.from.id, message.from.first_name})
api.send_message(message.chat.id, 'Welcome, ' .. name .. '!', {
parse_mode = 'HTML',
reply_markup = api.inline_keyboard()
:row(api.row()
:callback_data_button('Help', 'help')
:callback_data_button('Ask AI', 'ai'))
})
elseif cmd and cmd.command == 'ask' and cmd.args_str then
api.send_typing(message.chat.id)
local result = llm:chat({{ role = 'user', content = cmd.args_str }})
api.send_message(message.chat.id, result and result.content or 'Sorry, error occurred.')
end
end
api.run({ timeout = 60 })src/
main.lua -- Entry point, core HTTP, module loader
config.lua -- API endpoint configuration
polyfill.lua -- Lua 5.1+ compatibility (bit ops, string.pack)
async.lua -- Copas-based concurrency module
b64url.lua -- Base64 URL encoding/decoding
tools.lua -- Utility functions (formatting, file ops, etc.)
handlers.lua -- Update routing and on_* handler stubs (async-first)
builders.lua -- Keyboard, inline result, and type constructors
helpers.lua -- Member status check helpers
utils.lua -- Bot development utilities (fmt, commands, pagination)
compat.lua -- v2 backward compatibility layer
adapters/
init.lua -- Adapter registry and shared utilities
db.lua -- Database adapter (SQLite, PostgreSQL)
redis.lua -- Redis adapter (RESP protocol)
llm.lua -- LLM adapter (OpenAI, Anthropic)
email.lua -- Email adapter (SMTP)
methods/
messages.lua -- send_*, forward_*, copy_*, edit_*, delete_*
updates.lua -- get_updates, webhooks
chat.lua -- Chat management
members.lua -- Member management (ban, restrict, promote)
forum.lua -- Forum topic management
stickers.lua -- Sticker operations
inline.lua -- Inline queries and callback queries
payments.lua -- Invoices, payments, stars
games.lua -- Game methods
passport.lua -- Passport data errors
bot.lua -- Bot profile and settings
gifts.lua -- Gift methods
checklists.lua -- Checklist methods
stories.lua -- Story methods
suggested_posts.lua -- Suggested post methods
luarocks install busted
busted
v3 includes a compatibility layer that lets most v2 code run with deprecation warnings. Here's what to do:
luarocks install telegram-bot-lua
LuaRocks handles dependency changes automatically (lpeg and html-entities removed, copas added).
-- v2
local api = require('telegram-bot-lua.core').configure('TOKEN')
-- v3
local api = require('telegram-bot-lua').configure('TOKEN')The old require('telegram-bot-lua.core') still works but prints a deprecation warning.
v3 uses options tables instead of positional args. The compat layer auto-detects v2-style calls and converts them, but you should update your code:
-- v2
api.send_message(chat_id, text, nil, 'HTML', nil, nil, false, false, reply_params, reply_markup)
api.send_photo(chat_id, photo, nil, 'Caption', 'HTML')
api.answer_callback_query(id, 'Alert text', true)
api.edit_message_text(chat_id, msg_id, text, 'HTML')
api.run(1, 60)
-- v3
api.send_message(chat_id, text, { parse_mode = 'HTML', reply_parameters = reply_params, reply_markup = reply_markup })
api.send_photo(chat_id, photo, { caption = 'Caption', parse_mode = 'HTML' })
api.answer_callback_query(id, { text = 'Alert text', show_alert = true })
api.edit_message_text(chat_id, msg_id, text, { parse_mode = 'HTML' })
api.run({ timeout = 60 })These v2 methods are aliased with deprecation warnings:
| v2 | v3 |
|---|---|
kick_chat_member(chat_id, user_id, until_date) |
ban_chat_member(chat_id, user_id, opts) |
get_chat_members_count(chat_id) |
get_chat_member_count(chat_id) |
api.run() uses copas for concurrent update processing. Each handler runs in its own coroutine. For the old sequential behaviour:
api.run({ sync = true, timeout = 60 })- Handler functions (
api.on_message,api.on_callback_query, etc.) — same pattern - Builder methods (
api.keyboard(),api.inline_keyboard(), etc.) — same API - Tool functions (
tools.escape_html,tools.comma_value, etc.) — same API - No config files, secrets, or environment variables to migrate
This project is licensed under the GPL-3.0 License - see the LICENSE file for details.
Copyright (c) 2017-2026 Matthew Hesketh