Low-level HTTP client for the Telegram Bot API.
Every method builds a JSON (or multipart) body and POSTs it to
https://api.telegram.org/bot<TOKEN>/<method>.
Most users don't need to call this module directly — use Sexy.Bot which
delegates here. For any Telegram method not explicitly wrapped, call request/2:
body = Jason.encode!(%{chat_id: 123, text: "hi"})
Sexy.Bot.Api.request(body, "sendMessage")Timeouts
- JSON requests: 5 seconds (configurable via opts)
- Multipart uploads: 20 seconds
- Polling (
get_updates): 10 seconds
Return values
All methods return decoded JSON as a map:
%{"ok" => true, "result" => %{...}}
%{"ok" => false, "description" => "..."}
Summary
Functions
Delete a message from a chat.
Show a chat action indicator. action is a Telegram action string, e.g.
"typing", "upload_photo", "upload_video", "record_voice".
Send a dice animation. emoji is one of Telegram's dice emoji:
"🎲", "🎯", "🏀", "⚽", "🎳", "🎰".
Run fun (an API call returning a tg_response) and, on a Telegram 429 rate
limit, sleep the advertised retry_after and try once more.
Types
@type tg_response() :: map()
Functions
@spec answer_callback(map()) :: tg_response()
@spec answer_callback(String.t(), String.t(), boolean()) :: tg_response()
@spec answer_pre_checkout(String.t()) :: tg_response()
@spec copy_message(integer(), integer(), integer()) :: tg_response()
@spec delete_commands() :: tg_response()
@spec delete_message(integer(), integer(), keyword()) :: tg_response() | {:ok, pid()}
Delete a message from a chat.
Options
:after— delay in seconds before deleting. Accepts integers and floats. When provided, deletion runs asynchronously in a supervised background task. Best-effort: pending deletions are lost if the node restarts before the delay elapses.
Examples
# Immediate deletion
delete_message(chat_id, message_id)
# Delete after 5 seconds
delete_message(chat_id, message_id, after: 5)
# Delete after half a second
delete_message(chat_id, message_id, after: 0.5)
@spec edit_media(String.t()) :: tg_response()
@spec edit_reply_markup(String.t()) :: tg_response()
@spec edit_text(map()) :: tg_response()
@spec forward_message(String.t()) :: tg_response()
@spec get_chat(integer()) :: tg_response()
@spec get_chat_member(integer(), integer()) :: tg_response()
@spec get_me() :: tg_response()
@spec refund_star_payment(integer(), String.t()) :: tg_response()
@spec request(String.t(), String.t()) :: tg_response()
@spec send_animation(String.t()) :: tg_response()
@spec send_chat_action(integer(), String.t()) :: tg_response()
Show a chat action indicator. action is a Telegram action string, e.g.
"typing", "upload_photo", "upload_video", "record_voice".
@spec send_dice(integer(), String.t()) :: tg_response()
Send a dice animation. emoji is one of Telegram's dice emoji:
"🎲", "🎯", "🏀", "⚽", "🎳", "🎰".
@spec send_message(String.t()) :: tg_response()
@spec send_message(integer(), String.t()) :: tg_response()
@spec send_photo(String.t()) :: tg_response()
@spec send_poll(String.t()) :: tg_response()
@spec send_video(String.t()) :: tg_response()
@spec set_commands(String.t()) :: tg_response()
@spec with_429_retry((-> tg_response())) :: tg_response()
Run fun (an API call returning a tg_response) and, on a Telegram 429 rate
limit, sleep the advertised retry_after and try once more.
Safe to retry: a 429 means the request was rejected, not executed, and both
send and edit are idempotent. Non-429 responses (incl. permanent errors like
BUTTON_DATA_INVALID) are returned unchanged — no retry.