{"id":13836617,"url":"https://github.com/visciang/telegram","last_synced_at":"2026-05-14T08:06:09.969Z","repository":{"id":37451166,"uuid":"103292387","full_name":"visciang/telegram","owner":"visciang","description":"Telegram library for the Elixir language","archived":false,"fork":false,"pushed_at":"2026-02-13T09:53:14.000Z","size":1684,"stargazers_count":242,"open_issues_count":1,"forks_count":30,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-02-13T17:53:50.709Z","etag":null,"topics":["bot","elixir","telegram"],"latest_commit_sha":null,"homepage":"","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/visciang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":["visciang"],"custom":["https://paypal.me/visciang"]}},"created_at":"2017-09-12T16:02:45.000Z","updated_at":"2026-02-13T09:49:27.000Z","dependencies_parsed_at":"2023-02-15T23:45:37.523Z","dependency_job_id":"77d621c9-4d2f-4720-a691-d8438850ee1d","html_url":"https://github.com/visciang/telegram","commit_stats":null,"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"purl":"pkg:github/visciang/telegram","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/visciang%2Ftelegram","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/visciang%2Ftelegram/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/visciang%2Ftelegram/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/visciang%2Ftelegram/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/visciang","download_url":"https://codeload.github.com/visciang/telegram/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/visciang%2Ftelegram/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33015831,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-13T13:14:54.681Z","status":"online","status_checked_at":"2026-05-14T02:00:06.663Z","response_time":57,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bot","elixir","telegram"],"created_at":"2024-08-04T15:00:51.072Z","updated_at":"2026-05-14T08:06:09.964Z","avatar_url":"https://github.com/visciang.png","language":"Elixir","funding_links":["https://github.com/sponsors/visciang","https://paypal.me/visciang"],"categories":["Elixir"],"sub_categories":[],"readme":"# Telegram\n\n[![.github/workflows/ci.yml](https://github.com/visciang/telegram/actions/workflows/ci.yml/badge.svg)](https://github.com/visciang/telegram/actions/workflows/ci.yml) [![Docs](https://img.shields.io/badge/docs-latest-green.svg)](https://visciang.github.io/telegram/readme.html) [![Coverage Status](https://coveralls.io/repos/github/visciang/telegram/badge.svg?branch=master)](https://coveralls.io/github/visciang/telegram?branch=master)\n\nTelegram library for the Elixir language.\n\nIt provides:\n- an inteface to the Telegram Bot HTTP-based APIs (`Telegram.Api`)\n- a couple of bot behaviours to define you bots (`Telegram.Bot`, `Telegram.ChatBot`)\n- two bot runners (`Telegram.Poller`, `Telegram.Webhook`)\n\n## Installation\n\nThe package can be installed by adding `telegram` to your list of dependencies in `mix.exs`:\n\n```elixir\ndef deps do\n  [\n    {:telegram, github: \"visciang/telegram\", tag: \"xxx\"}\n  ]\nend\n```\n\n# Telegram Bot API\n\nThis module expose a light layer over the Telegram Bot API HTTP-based interface,\nit does not expose any \"(data)binding\" over the HTTP interface and tries to abstract\naway only the boilerplate for building / sending / serializing the API requests.\n\nCompared to a full data-binded interface it could result less \"typed frendly\" but it will\nwork with any version of the Bot API, hopefully without updates or incompatibily\nwith new Bot API versions (as much as they remain backward compatible).\n\n\nReferences:\n* [API specification](https://core.telegram.org/bots/api)\n* [Bot intro for developers](https://core.telegram.org/bots)\n\nGiven the token of your Bot you can issue any request using:\n* method: Telegram API method name (ex. \"getMe\", \"sendMessage\")\n* options: Telegram API method specific parameters (you can use Elixir's native types)\n\n## Examples:\n\nGiven the bot token (something like):\n\n```elixir\ntoken = \"123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11\"\n```\n\n### [getMe](https://core.telegram.org/bots/api#getme)\n\n```elixir\nTelegram.Api.request(token, \"getMe\")\n\n{:ok, %{\"first_name\" =\u003e \"Abc\", \"id\" =\u003e 1234567, \"is_bot\" =\u003e true, \"username\" =\u003e \"ABC\"}}\n```\n\n### [sendMessage](https://core.telegram.org/bots/api#sendmessage)\n\n```elixir\nTelegram.Api.request(token, \"sendMessage\", chat_id: 876532, text: \"Hello! .. silently\", disable_notification: true)\n\n{:ok,\n  %{\"chat\" =\u003e %{\"first_name\" =\u003e \"Firstname\",\n      \"id\" =\u003e 208255328,\n      \"last_name\" =\u003e \"Lastname\",\n      \"type\" =\u003e \"private\",\n      \"username\" =\u003e \"xxxx\"},\n    \"date\" =\u003e 1505118722,\n    \"from\" =\u003e %{\"first_name\" =\u003e \"Yyy\",\n      \"id\" =\u003e 234027650,\n      \"is_bot\" =\u003e true,\n      \"username\" =\u003e \"yyy\"},\n    \"message_id\" =\u003e 1402,\n    \"text\" =\u003e \"Hello! .. silently\"}}\n```\n\n### [getUpdates](https://core.telegram.org/bots/api#getupdates)\n\n```elixir\nTelegram.Api.request(token, \"getUpdates\", offset: -1, timeout: 30)\n\n{:ok,\n  [%{\"message\" =\u003e %{\"chat\" =\u003e %{\"first_name\" =\u003e \"Firstname\",\n        \"id\" =\u003e 208255328,\n        \"last_name\" =\u003e \"Lastname\",\n        \"type\" =\u003e \"private\",\n        \"username\" =\u003e \"xxxx\"},\n      \"date\" =\u003e 1505118098,\n      \"from\" =\u003e %{\"first_name\" =\u003e \"Firstname\",\n        \"id\" =\u003e 208255328,\n        \"is_bot\" =\u003e false,\n        \"language_code\" =\u003e \"en-IT\",\n        \"last_name\" =\u003e \"Lastname\",\n        \"username\" =\u003e \"xxxx\"},\n      \"message_id\" =\u003e 1401,\n      \"text\" =\u003e \"Hello!\"},\n    \"update_id\" =\u003e 129745295}]}\n```\n\n## Sending files\n\nIf an API parameter has a `InputFile` type and you want to send a local file,\nfor example a photo stored at \"/tmp/photo.jpg\", just wrap the parameter\nvalue in a `{:file, \"/tmp/photo.jpg\"}` tuple. If the file content is in memory\nwrap it in a `{:file_content, data, \"photo.jpg\"}` tuple.\n\n### [sendPhoto](https://core.telegram.org/bots/api#sendphoto)\n\n```elixir\nTelegram.Api.request(token, \"sendPhoto\", chat_id: 876532, photo: {:file, \"/tmp/photo.jpg\"})\nTelegram.Api.request(token, \"sendPhoto\", chat_id: 876532, photo: {:file_content, photo, \"photo.jpg\"})\n```\n\n## Downloading files\n\nTo download a file from the telegram server you need a `file_path` pointer to the file.\nWith that you can download the file via `Telegram.Api.file`.\n\n```elixir\n{:ok, res} = Telegram.Api.request(token, \"sendPhoto\", chat_id: 12345, photo: {:file, \"example/photo.jpg\"})\n# pick the 'file_obj' with the desired resolution\n[file_obj | _] = res[\"photo\"]\n# get the 'file_id'\nfile_id = file_obj[\"file_id\"]\n```\n\n### [getFile](https://core.telegram.org/bots/api#getfile)\n\n```elixir\n{:ok, %{\"file_path\" =\u003e file_path}} = Telegram.Api.request(token, \"getFile\", file_id: file_id)\n{:ok, file} = Telegram.Api.file(token, file_path)\n```\n\n## JSON-serialized object parameters\n\nIf an API parameter has a non primitive scalar type it is explicitly pointed out as \"A JSON-serialized object\"\n(ie `InlineKeyboardMarkup`, `ReplyKeyboardMarkup`, etc).\nIn this case you can wrap the parameter value in a `{:json, value}` tuple.\n\n### [sendMessage](https://core.telegram.org/bots/api#sendmessage) with keyboard\n\n```elixir\nkeyboard = [\n  [\"A0\", \"A1\"],\n  [\"B0\", \"B1\", \"B2\"]\n]\nkeyboard_markup = %{one_time_keyboard: true, keyboard: keyboard}\nTelegram.Api.request(token, \"sendMessage\", chat_id: 876532, text: \"Here a keyboard!\", reply_markup: {:json, keyboard_markup})\n```\n\n## Sending files inside JSON-serialized objects\n\nSometimes you need to send a file inside a JSON-serialized object. A typical example is `editMessageMedia`, where the `media` parameter is an `InputMedia` object, which can contain a file.\n\nIn this case, you can send the file as a separate top-level parameter and reference it inside the JSON object using the `attach://\u003cparam_name\u003e` syntax. The library will automatically switch to a `multipart/form-data` request.\n\n### [editMessageMedia](https://core.telegram.org/bots/api#editmessagemedia)\n\n```elixir\nparams = [\n  chat_id: chat_id,\n  message_id: some_message_id,\n  # The file is sent as a top-level parameter\n  _file: {:file_content, file_data, \"video.mp4\"},\n  # The media parameter is a JSON-serialized object\n  media:\n    {:json,\n     %{\n       type: \"video\",\n       # The file is referenced here\n       media: \"attach://_file\"\n     }}\n]\nTelegram.Api.request(token, \"editMessageMedia\", params)\n```\n\n# Telegram Bot\n\n## Quick start\n\nCheck the examples under `example/example_*.exs`.\nYou can run them as a `Mix` self-contained script.\n\n```shell\nBOT_TOKEN=\"...\" example/example_chatbot.exs\n```\n\n## Bot updates processing\n\nThe Telegram platform supports two ways of processing bot updates, `getUpdates` and `setWebhook`.\n`getUpdates` is a pull mechanism, `setWebhook` is a push mechanism. (ref: [bots webhook](https://core.telegram.org/bots/webhooks))\n\nThis library currently implements both models via two supervisors.\n\n### Poller\n\nThis mode can be used in a dev environment or if your bot doesn't need to \"scale\". Being in pull it works well behind a firewall (or behind a home internet router).\nRefer to the `Telegram.Poller` module docs for more info.\n\n\n#### Telegram Client Config\n\nThe Telegram HTTP Client is based on `Tesla`.\n\nThe `Tesla.Adapter` and options should be configured via the `[:tesla, :adapter]` application environment key.\n(ref. https://hexdocs.pm/tesla/readme.html#adapters)\n\nFor example, a good default could be:\n\n```elixir\nconfig :tesla, adapter: {Tesla.Adapter.Hackney, [recv_timeout: 40_000]}\n```\n\na dependency should be added accordingly in your `mix.exs`:\n\n```elixir\n defp deps do\n    [\n      {:telegram, github: \"visciang/telegram\", tag: \"xxx\"},\n      {:hackney, \"~\u003e 1.18\"},\n      # ...\n    ]\n  end\n```\n\n### Webhook\n\nThis mode interfaces with the Telegram servers via a webhook, best for production use.\nThe app is meant to be served over HTTP, a reverse proxy should be placed in front of it, facing the public network over HTTPS.\nIt's possible to use two `Plug` compatible webserver: `Bandit` and `Plug.Cowboy`.\n\nAlternatively, if you have a `Phoenix` / `Plug` based application facing internet, you can directly integrate the webhook.\n\nRefer to the `Telegram.Webhook` module docs for more info.\n\n## Dispatch model\n\nWe can define stateless / stateful bot.\n\n* A stateless Bot has no memory of previous conversations, it just receives updates, process them and so on.\n\n* A stateful Bot instead can remember what happened in the past.\nThe state here refer to a specific chat, a conversation (chat_id) between a user and a bot \"instance\".\n\n## Bot behaviours\n\n* `Telegram.Bot`: works with the **stateless async** dispatch model\n* `Telegram.ChatBot`: works with the **stateful chat** dispatch model\n\n## Logging\n\nThe library attaches two metadata fields to the internal logs: [:bot, :chat_id].\nIf your app runs more that one bot these fields can be included in your logs (ref. to the Logger config)\nto clearly identify and \"trace\" every bot's message flow.\n\n# Sample app\n\nA chat_bot app, deployed to Gigalixir PaaS and served in webhook mode: https://github.com/visciang/telegram_example\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvisciang%2Ftelegram","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvisciang%2Ftelegram","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvisciang%2Ftelegram/lists"}