Sexy.Bot (Sexy v0.9.13)

Copy Markdown View Source

Telegram Bot API framework with the single-message UI pattern.

Starting

Add to your supervision tree with a bot token and a module implementing Sexy.Bot.Session:

children = [
  {Sexy.Bot, token: System.get_env("BOT_TOKEN"), session: MyApp.Session}
]

Core workflow

The typical flow inside a session callback:

# 1. Build an Object from a plain map
object = Sexy.Bot.build(%{
  chat_id: chat_id,
  text: "Pick an option:",
  kb: %{inline_keyboard: [[%{text: "Go", callback_data: "/go"}]]}
})

# 2. Send it — old message is deleted, new one saved automatically
Sexy.Bot.send(object)

Single-message pattern

Each chat has one active message (screen). When you call send/1, Sexy:

  1. Detects content type (text, photo, video, animation, document)
  2. Calls the appropriate Telegram API method
  3. Deletes the previous message via Session.get_message_id/1
  4. Saves the new message id via Session.on_message_sent/4

This creates an app-like experience where the UI updates in place.

Sending files

To upload a local file or binary, set upload_type together with file and filename. Supported types: :photo, :video, :animation, :document.

Sexy.Bot.build(%{
  chat_id: chat_id,
  upload_type: :document,
  file: File.read!("report.csv"),
  filename: "report.csv",
  text: "Here is your report"
})
|> Sexy.Bot.send()

Sexy.Bot.build(%{
  chat_id: chat_id,
  upload_type: :photo,
  file: File.read!("pic.jpg"),
  filename: "pic.jpg",
  text: "<b>Look</b>"
})
|> Sexy.Bot.send()

The legacy media: "file" sentinel still works for documents and is equivalent to upload_type: :document.

Notifications

Use notify/3 for messages that don't replace the current screen:

# Overlay with dismiss button
Sexy.Bot.notify(chat_id, %{text: "Saved!"})

# Replace current screen
Sexy.Bot.notify(chat_id, %{text: "Payment received!"}, replace: true)

# With navigation button
Sexy.Bot.notify(chat_id, %{text: "New order!"}, navigate: {"View", "/order id=42"})

Telegram API

All standard Telegram Bot API methods are available as delegates: send_message/2, send_photo/1, edit_text/1, delete_message/2, answer_callback/3, send_invoice/6, and more. For any method not wrapped, use request/2.

Summary

Functions

Answer a callback query with a pre-built map.

Answer a callback query with text and optional alert popup.

Confirm a pre-checkout query (for Telegram Payments).

Convert a map (or list of maps) into Sexy.Utils.Object struct(s).

Returns a specification to start this module under a supervisor.

Copy a message to another chat.

Delete all bot menu commands.

Delete a message. Pass after: seconds to delay deletion.

Edit message media. Body is a JSON-encoded string.

Edit message reply markup (buttons). Body is a JSON-encoded string.

Edit message text. Body is a map with :chat_id, :message_id, :text, etc.

Forward a message. Body is a JSON-encoded string.

Get chat info by chat_id.

Get chat member info.

Get bot info (getMe API method).

Poll for updates starting from the given offset. See Sexy.Bot.Api.get_updates/1.

Get the highest-resolution profile photo file_id for a user.

Send a notification message with optional dismiss/navigate buttons.

Refund a Telegram Stars payment.

Call any Telegram Bot API method by name.

Send an Object (or list of Objects) to Telegram.

Send an animation (GIF) by file_id. Body is a JSON-encoded string.

Upload an animation as multipart. file is a binary or path; kb is a JSON-encoded reply markup.

Show a chat action indicator. Type is one of: "txt" (typing), "pic" (uploading photo), "vid" (uploading video).

Send a dice animation. Type is one of: "dice", "bowl", "foot", "bask", "dart", "777".

Send a document as multipart upload.

Send a pre-encoded JSON body as a message.

Send a text message with HTML parse mode.

Send a photo by file_id. Body is a JSON-encoded string.

Upload a photo as multipart. file is a binary or path; kb is a JSON-encoded reply markup.

Send a poll. Body is a JSON-encoded string.

Send a video by file_id. Body is a JSON-encoded string.

Upload a video as multipart. file is a binary or path; kb is a JSON-encoded reply markup.

Set bot menu commands from a comma-separated string.

Create a Wallet.tg payment order. Reads WALLET env var for the API key.

Types

tg_response()

@type tg_response() :: map()

Functions

answer_callback(obj)

Answer a callback query with a pre-built map.

answer_callback(callback_id, text, alert)

Answer a callback query with text and optional alert popup.

answer_pre_checkout(pre_checkout_query_id)

Confirm a pre-checkout query (for Telegram Payments).

build(map)

@spec build(map() | [map()]) :: Sexy.Utils.Object.t() | [Sexy.Utils.Object.t()]

Convert a map (or list of maps) into Sexy.Utils.Object struct(s).

Accepts any map with Object fields: :chat_id, :text, :media, :kb, :entity, :update_data, :file, :filename, :upload_type.

Example

Sexy.Bot.build(%{chat_id: 123, text: "Hello!"})
#=> %Sexy.Utils.Object{chat_id: 123, text: "Hello!", ...}

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

copy_message(chat_id, from_chat_id, message_id)

Copy a message to another chat.

delete_commands()

Delete all bot menu commands.

delete_message(chat_id, message_id, opts \\ [])

Delete a message. Pass after: seconds to delay deletion.

Examples

Sexy.Bot.delete_message(chat_id, mid)
Sexy.Bot.delete_message(chat_id, mid, after: 5)

edit_media(body)

Edit message media. Body is a JSON-encoded string.

edit_reply_markup(body)

Edit message reply markup (buttons). Body is a JSON-encoded string.

edit_text(body)

Edit message text. Body is a map with :chat_id, :message_id, :text, etc.

forward_message(body)

Forward a message. Body is a JSON-encoded string.

get_chat(chat_id)

Get chat info by chat_id.

get_chat_member(chat_id, user_id)

Get chat member info.

get_me()

Get bot info (getMe API method).

get_updates(offset)

Poll for updates starting from the given offset. See Sexy.Bot.Api.get_updates/1.

get_user_photo(user_id)

Get the highest-resolution profile photo file_id for a user.

notify(chat_id, msg, opts \\ [])

@spec notify(integer(), map(), keyword()) :: tg_response()

Send a notification message with optional dismiss/navigate buttons.

See Sexy.Bot.Notification for full option details.

Examples

Sexy.Bot.notify(chat_id, %{text: "Done!"})
Sexy.Bot.notify(chat_id, %{text: "Saved!"}, after: 3)
Sexy.Bot.notify(chat_id, %{text: "Order!"}, navigate: {"View", "/order"}, after: 10)

refund_star_payment(user_id, charge_id)

Refund a Telegram Stars payment.

request(body, method)

Call any Telegram Bot API method by name.

Example

body = Jason.encode!(%{chat_id: 123, text: "hi"})
Sexy.Bot.request(body, "sendMessage")

send(object, opts \\ [])

@spec send(
  Sexy.Utils.Object.t() | [Sexy.Utils.Object.t()],
  keyword()
) :: tg_response() | :ok

Send an Object (or list of Objects) to Telegram.

Handles the full single-message lifecycle: detect type, call API, delete old message, save new message id via Session.

Options

  • :update_midtrue (default) to manage the active message, false to send without touching screen state

Examples

# Send a text screen
%{chat_id: id, text: "Hello"}
|> Sexy.Bot.build()
|> Sexy.Bot.send()

# Send without replacing the current screen
Sexy.Bot.send(object, update_mid: false)

send_animation(body)

Send an animation (GIF) by file_id. Body is a JSON-encoded string.

send_animation(chat_id, file, filename, text, kb)

Upload an animation as multipart. file is a binary or path; kb is a JSON-encoded reply markup.

send_chat_action(chat_id, type)

Show a chat action indicator. Type is one of: "txt" (typing), "pic" (uploading photo), "vid" (uploading video).

send_dice(chat_id, type)

Send a dice animation. Type is one of: "dice", "bowl", "foot", "bask", "dart", "777".

send_document(chat_id, file, name, text, kb)

Send a document as multipart upload.

Parameters

  • chat_id — Telegram chat id
  • file — binary file content
  • name — filename shown to the user
  • text — caption (HTML)
  • kb — JSON-encoded reply markup

send_invoice(chat_id, title, description, payload, currency, prices)

Send a Telegram Stars invoice.

send_message(body)

Send a pre-encoded JSON body as a message.

send_message(chat_id, text)

Send a text message with HTML parse mode.

send_photo(body)

Send a photo by file_id. Body is a JSON-encoded string.

send_photo(chat_id, file, filename, text, kb)

Upload a photo as multipart. file is a binary or path; kb is a JSON-encoded reply markup.

send_poll(body)

Send a poll. Body is a JSON-encoded string.

send_video(body)

Send a video by file_id. Body is a JSON-encoded string.

send_video(chat_id, file, filename, text, kb)

Upload a video as multipart. file is a binary or path; kb is a JSON-encoded reply markup.

set_commands(string)

Set bot menu commands from a comma-separated string.

Example

Sexy.Bot.set_commands("start - Launch bot, help - Show help")

start_link(opts)

@spec start_link(keyword()) :: Supervisor.on_start()

wallet_init(cur, sum, id, info, user)

Create a Wallet.tg payment order. Reads WALLET env var for the API key.