
ExGram is a powerful Elixir library for building Telegram Bots. Use the low-level API for fine-grained control, or leverage the opinionated framework for rapid bot development.
Features
- Automatic API Generation - Always up-to-date with the latest Telegram Bot API
- Flexible DSL - Build responses elegantly with the context-based DSL
- Polling & Webhooks - Choose the update method that fits your needs
- Easy discovery of the API - Complete typespecs and documentation for all methods and models
- Middleware System - Add authentication, logging, and custom processing
- Message Entities Builder - Easily format messages without Markdown/HTML escaping
- Multiple Bots - Run multiple different bots, or instances of the same bot in a single application
- Production Ready - Battle-tested in real-world applications
Quick Start
Installation
Add to your mix.exs:
def deps do
[
{:ex_gram, "~> 0.64"},
{:jason, "~> 1.4"},
{:req, "~> 0.5"} # HTTP adapter
]
endConfigure the adapter:
# config/config.exs
config :ex_gram, adapter: ExGram.Adapter.ReqConfigure the formatter (Optional):
# .formatter.exs
[
# ....
import_deps: [:ex_gram] # Add :ex_gram here
]Your First Bot
Generate a bot module:
mix bot.new
Add to your supervision tree:
# lib/my_app/application.ex
def start(_type, _args) do
children = [
ExGram,
{MyApp.Bot, [method: :polling, token: "YOUR_BOT_TOKEN"]}
]
Supervisor.start_link(children, strategy: :one_for_one)
endImplement handlers:
defmodule MyApp.Bot do
use ExGram.Bot, name: :my_bot, setup_commands: true
import ExGram.Dsl.Keyboard
command("start")
command("help", description: "Show help")
middleware(ExGram.Middleware.IgnoreUsername)
def handle({:command, :start, _}, context) do
answer(context, "Welcome! I'm your bot.")
end
def handle({:command, :help, _}, context) do
message = """
Available commands:
/start - Start the bot
/help - Show this help
"""
keyboard =
keyboard :inline do
row do
button "Test button", callback_data: "button"
end
end
answer(context, message, reply_markup: keyboard)
end
def handle({:callback_query, %{data: "button"}}, context) do
context
|> answer_callback("Button clicked!")
|> edit(:inline, "You clicked the button!")
end
endRun your bot:
mix run --no-halt
DSL Functions
The ExGram DSL builds actions on the context that execute after your handler returns.
Sending Messages
context
|> answer("Hello!")
|> answer_document({:file, "/path/to/file.pdf"})Inline Keyboards
- With the DSL
import ExGram.Dsl.Keyboard
markup =
keyboard :inline do
row do
button "Button text", callback_data: "button"
end
end
answer(context, "Choose:", reply_markup: markup)- With a helper method
markup = create_inline_keyboard([
[%{text: "Button", callback_data: "button"}]
])
answer(context, "Choose:", reply_markup: markup)Editing & Deleting
edit(context, "Updated message")
edit_markup(context, new_keyboard)
delete(context)Callback Queries & Inline Queries
answer_callback(context, "Processing...")
answer_inline_query(context, results)Use steps results
context
|> answer("Important message!")
|> on_result(fn
{:ok, message}, name ->
ExGram.pin_chat_message(message.chat.id, message.message_id, bot: name)
error, _name ->
error
end)Extracting Information
extract_id(context) # Chat ID
extract_user(context) # User
extract_message_id(context) # Message ID
extract_update_type(context) # Update type
extract_message_type(context) # Message typeLow-Level API
Use ExGram as a library without the framework:
# Configure globally
config :ex_gram, token: "YOUR_TOKEN"
ExGram.send_photo(chat_id, {:file, "photo.jpg"})
ExGram.get_me()
# Or you can pass the token directly
ExGram.send_message(chat_id, "Hello!", token: "YOUR_TOKEN")All methods return {:ok, result} | {:error, ExGram.Error.t()} and have bang variants:
{:ok, message} = ExGram.send_message(chat_id, "Hello")
message = ExGram.send_message!(chat_id, "Hello") # Raises on errorSee the Sending Messages guide for a complete reference or the Cheatsheet for a quick overview.
Documentation
Getting Started
- Installation - HTTP adapters, JSON engines, configuration
- Getting Started - Create your first bot
Building Bots
- Handling Updates - Process commands, messages, and other updates
- Sending Messages - DSL philosophy and response building
- Define commands - Clearly define you bot's commands, with options for different scopes and languages
- Message Entities - Format messages without dealing with MarkdownV2 or HTML
- Middlewares - Add preprocessing logic
Advanced
- Polling and Webhooks - Configure update methods
- Low-Level API - Direct API calls for complex scenarios
- Multiple Bots - Run multiple bots in one application
- Bot Init Hooks - Run custom code during bot startup
- Testing - Test your bots
Deployment
- Fly.io - Deploy your bot to production
Reference
- Cheatsheet - Quick reference for common patterns
- HexDocs - Complete API documentation
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
Beer-Ware License. See LICENSE for details.
Links
- Telegram Bot API Documentation
- HexDocs
- Hex Package
- telegram_api_json - API JSON generator