# Change Log All notable changes to this project will be documented in this file. This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased][Unreleased] ## [2.2.0-rc2][2.2.0-rc2] - 2026-09-07 ### Reply and callback tracking - Renamed the reply-tracking size budgets to denote their scope: `replyTracking.maxEntries` -> `maxEntriesPerChat` and `maxBytes` -> `maxBytesPerChat` (each bounds one session key's tables, per chat with the default key). Breaking rename within the `2.2.0` prerelease line; the old names shipped only in `2.2.0-rc1`. ### Maintenance - Simplified core functions and added Biome formatting and complexity checks to CI (#1364, #1365). - Removed obsolete v2 migration references, corrected file attachment and serialization comments, and regenerated the API reference (#1366). ## [2.2.0-rc1][2.2.0-rc1] - 2026-09-07 ### Long polling - A `409 Conflict` is now treated as a recoverable poll error instead of permanently stopping the loop (#1350). Added `LongPollOptions.conflictRetryDelayMs` (default 5000ms) and `maxConflictRetries` (default 10) - after that many consecutive conflicts (a genuine two-instance deploy) the loop throws. The existing `retry` toggle now also governs 409s. Added the public `isPollConflict()` predicate and the `HTTP_STATUS_CONFLICT` constant. ### Transport - An empty or whitespace-only `apiRoot` now falls back to the default API root instead of being used verbatim (which produced malformed request URLs) (#1354). ### Node helpers - `run()` gained an opt-in `exitOnError` (default `false`): when a polling pump fails fatally, the process exits non-zero after teardown instead of staying alive and silent, so a supervisor can restart it (#1351). - `RedisSessionStorage` now owns and closes a client it constructs from a `url`, via a `createClient` seam (#1351). ### Reply and callback tracking - Added an opt-in per-chat **LRU bound** on the reply/press tables, configured on the session: `createSession({ store, replyTracking: { maxEntries, maxBytes, defaultTtlSeconds, slidingTtl } })`. `ttlSeconds` caps a marker's age but not the table's size, so a chat that fires many short-lived keyboards could still grow its envelope between prunes (#1357). - `maxEntries` / `maxBytes` cap the tables (combined across replies and presses), evicting the **least-recently-used** markers once a budget is exceeded - recency, not age, so an actively-pressed old keyboard outlives an idle newer one; a match refreshes recency, not just a record. `defaultTtlSeconds` gives every expectation a TTL, and `slidingTtl` re-arms it on use. - All fields are optional; with no `replyTracking` the tables stay unbounded, as before. Recency metadata (`lastUsedAt`) is written only when a size budget (`maxEntries` / `maxBytes`) is set, so configs without one keep byte-identical envelopes. - Added the example `examples/18-reply-tracking-lru.ts`. ### Sessions - Dropped the `createdAt` / `updatedAt` envelope timestamps (and the `now` clock option that fed them): nothing read them, and slimming the envelope directly serves the growth the LRU bound targets. Stale timestamp fields on already-stored rows fall out on the next write. (These shipped only in `2.2.0-rc0`.) ## [2.2.0-rc0][2.2.0-rc0] - 2026-09-03 ### Sessions - Added opt-in session middleware: `createSession(options)` (aliased `session`) attaches a persistent, keyed bag reached with `ctx.getSession()`. The `store` is required - there is no implicit default, so the durability choice is always explicit. The returned middleware also carries `.get(ctx)` / `.find(ctx)`, typed once at construction. - Added the `SessionStore` contract: a value-agnostic **string** KV - `read(key)`, `write(key, value, { ttlSeconds })`, `delete(key)`, plus optional `touch(key, ttlSeconds)`, `init()` and `close()`. Encoding happens once in the middleware's codec, never inside a store, so an in-memory store round-trips exactly like a durable one. - Added the stores: `MemorySessionStorage` (core, edge-safe, optional TTL), `FileSessionStorage` (`/node`, one file per key, atomic temp-file + `rename`), and, behind the new `./bun` subpath, `SqliteSessionStorage`, `SqlSessionStorage` and `RedisSessionStorage`. - The persisted value is a versioned envelope, `{ v, data, ext, createdAt, updatedAt }`. `ext` is a namespace map that layers built on sessions claim a slot in; the timestamps are first-seen / last-active, and the two SQL stores mirror them as `created_at` / `updated_at` columns. - The flush is skipped when the encoded envelope is unchanged, so an untouched chat costs one read and no write; `touch()` refreshes a TTL in that case. `ctx.getSession().delete()` evicts a key. - Updates for one key are serialized in-process by a per-key lock, so concurrent webhook invocations cannot interleave read-modify-write. Across processes it is last-writer-wins. ### Reply and callback tracking - Added `expectReply(ctx, messageId, marker?, { ttlSeconds? })`, `matchReply(ctx)` and `forgetReply(ctx, messageId)` - "awaiting a reply to this message" recorded as persisted data (matched on `reply_to_message.message_id`), never a live continuation, so it survives a restart and works on serverless. - Added the callback-query peers `expectCallback(ctx, messageId, marker?, { ttlSeconds? })`, `matchCallback(ctx, { once? })` and `forgetCallback(ctx, messageId)`, keyed on `callback_query.message.message_id`. Matching a press does not consume the marker by default (a keyboard usually stays live for several presses); `{ once: true }` makes a button fire at most once - it consumes only that message's marker, and consumption happens before the handler runs. Plain `callback_data` remains the idiomatic router - these are for a marker over 64 bytes, one the client must not read, or a one-shot press. - Replies and presses are kept in **separate** tables, so a quoted reply to a message that also carries an inline keyboard cannot consume the button's marker. - Expectations never expire on their own (a prompt answered tomorrow is normal); `ttlSeconds` bounds one, and expired entries are pruned the next time the layer touches the session, so a bot that sets a TTL cannot grow its envelope without limit. There is no cap and no default. - Added `taggedReplies(ctx)` - `expect` / `match` / `forget` / `expectPress` / `matchPress` / `forgetPress` for plain string tags, typing both ends with one union. - Note the default session key is per chat, so in a group any member's reply or press matches a marker; carry the asker's id in the marker and check it when that matters. ### Bot lifecycle - Added `bot.init()` and `bot.close()`. A middleware carrying `init` / `close` is picked up by `use()` and by `on` / `command` / `hears`; setup runs once at startup (awaited by `startPolling()` and `handleUpdate()`) and teardown runs in reverse. `run()` (`/node`) closes on shutdown. - `init()` tracks completion per plugin, so a failure retries from the plugin that failed instead of re-running the ones that succeeded; `close()` closes only what initialized, attempts every teardown even if one throws, and reports failures afterwards (an `AggregateError` when several failed). ## [2.1.0][2.1.0] - 2026-08-24 ### Builders - Added `RichTextBuilder` - a fluent builder for the recursive `RichText` tree, covering every node kind (bold/italic/underline/code/url/mention/date_time/ custom_emoji/anchor/reference/...), with nesting via strings or nested builders. - Added `RichMessageBuilder` - a fluent builder for the `blocks` form of `InputRichMessage` (`sendRichMessage`/`sendRichMessageDraft`), covering every block type; nested blocks (list/blockquote/collage/slideshow/details) take a nested builder or callback, and media blocks embed `InputFile`s (hoisted to `attach://`). - Added `RichMessageButtonBuilder` for a single `RichMessageButton` (rich label, `style`, and one action), plus the `richMessageButton`, `richCaption`, `richTableCell`, and `richListItem` helpers. - Fixed the type generator so `RichText` models its true wire union (`string | RichText[] | ...nodes`); every `text: RichText` field now accepts a plain string or array, not only a node object. ### Bot API 10.3 (August 24, 2026) #### Rich Messages - Added `RichMessageButton`, `RichTextButton`, `RichBlockButtons`/`InputRichBlockButtons`, `RichBlockExpandableBlockQuotation`/`InputRichBlockExpandableBlockQuotation`, and `RichBlockDocument`/`InputRichBlockDocument`. - Added `is_compact` to `RichBlockTable` and `InputRichBlockTable`, `InputMediaDocument` to `InputRichMessageMedia.media`, and support for `tg://document?id=` upload links. #### Ephemeral Messages - Added `EphemeralMessageParameters` and replaced `receiver_user_id`/`callback_query_id` with `ephemeral_message_parameters` in the 13 supported send methods; added `ephemeral_message_parameters` to `sendRichMessage`. - Added `replace_callback_query_message` to `EphemeralMessageParameters`, file upload in `editEphemeralMessageMedia`, `show_caption_above_media` to `editEphemeralMessageCaption`, and `rich_message` to `editEphemeralMessageText`. - Added `can_send_welcome_messages` to `ChatAdministratorRights`, `ChatMemberAdministrator`, and `promoteChatMember`. #### Reply markup - Added `DisabledButton` and `disabled` on `InlineKeyboardButton`, plus `force_reply` on `InlineKeyboardMarkup` and `ReplyKeyboardMarkup`. #### General - Added `can_stop`/`keep_on_stop` to `sendMessageDraft` and `sendRichMessageDraft`. - Added `MessageGenerationStopped` and the `stopped_message_generation` update type. - Added `CommunityChatJoined` and `Message.community_chat_joined`. - Added `text`, `entities`, and `is_private` to `UniqueGiftInfo`. ## [2.0.0][2.0.0] - 2026-08-16 ### Bot API 10.2 (July 14, 2026) #### Rich Messages - Added `InputRichMessageMedia`, `InputMediaVoiceNote`, `InputRichBlock`, `InputRichBlockListItem`, and the 21 input rich-block variants. - Added `media` and `blocks` to `InputRichMessage`. #### Ephemeral Messages - Added `editEphemeralMessageText`, `editEphemeralMessageMedia`, `editEphemeralMessageCaption`, `editEphemeralMessageReplyMarkup`, and `deleteEphemeralMessage`. - Added ephemeral targeting parameters to the 13 supported send methods and ephemeral-message fields to `BotCommand`, `Message`, and `ReplyParameters`. #### Communities - Added `Community`, `CommunityChatAdded`, `CommunityChatRemoved`, and their related `Message` and `ChatFullInfo` fields. #### General - Added `BotSubscriptionUpdated` and the `subscription` update type. v2 is a from-scratch redesign with **no backward compatibility** with the v1 `TelegramBot` surface. There is no shim - the table below is the migration path. The core is runtime-agnostic (Node 18+, Bun, Deno, Cloudflare Workers, Vercel/Deno Edge); the client is a single generated `Api` class; dispatch is koa-style middleware over a per-update `Context`. ### Migrating from v1 | Before (v1) | After (v2) | |-------------|------------| | `const TelegramBot = require('node-telegram-bot-api')` | `import { Bot } from 'node-telegram-bot-api'` (or `const { Bot } = require(...)` - both work) | | `new TelegramBot(token, { polling: true })` | `const bot = new Bot(token); bot.startPolling()` | | `new TelegramBot(token)` (for raw API calls) | `const bot = new Bot(token); await bot.api.getMe()` | | `request.fetchOptions.dispatcher` / proxy options | inject a custom Undici `fetch`: `new Bot(token, { fetch: (url, init) => fetch(url, { ...init, dispatcher }) })` | | `bot.on('message', msg => ...)` | `bot.on('message', ctx => ...)` - a router over `Context`, not an `EventEmitter` | | `bot.onText(/\/echo (.+)/, (msg, m) => ...)` | `bot.hears(/\/echo (.+)/, ctx => { ctx.match[1] })` | | `bot.onReplyToMessage(chatId, msgId, ...)` | middleware reading `ctx.message.reply_to_message` | | `bot.sendMessage(chatId, text, opts)` | `bot.api.sendMessage({ chat_id, text, ...opts })` or, in a handler, `ctx.reply(text, opts)` | | `bot.sendMessage(id, t, { reply_markup: { inline_keyboard: [...] } })` | `ctx.reply(t, { reply_markup: new InlineKeyboardBuilder().text('A','a').build() })` | | `{ reply_markup: JSON.stringify(markup) }` (manual) | a plain object `{ inline_keyboard: [...] }` or a builder `.build()` - the field is a plain typed object; the pipeline serializes it | | `bot.sendPhoto(id, '/path/to/p.jpg')` | `bot.api.sendPhoto({ chat_id, photo: await fromPath('/path/to/p.jpg') })` (from `'node-telegram-bot-api/node'`) | | `bot.sendPhoto(id, fs.createReadStream(...))` | `bot.api.sendPhoto({ chat_id, photo: new InputFile(bytes) })` | | bare string = path **or** file_id (via `options.filepath`) | a bare string is **always** a `file_id`/URL; bytes go through `new InputFile()`/`fromPath()` | | `bot.sendMediaGroup(id, [{ type:'photo', media: stream }])` | `bot.api.sendMediaGroup({ chat_id, media: [{ type:'photo', media: new InputFile(bytes) }] })` (or the `MediaGroupBuilder`) | | webhook via `new TelegramBot(token, { webHook: { port } })` | `createWebhookServer(bot, { path })` (`/node`) or `webhookCallback(bot)` on any runtime | | `bot.setWebHook(url)` | `bot.api.setWebhook({ url })` | | `bot.startPolling()` / `bot.stopPolling()` / `bot.isPolling()` | `bot.startPolling()` / `bot.stop()` / `bot.isRunning()`, or `longPoll(bot.api, opts, signal)` directly | | `error.code === 'ETELEGRAM'`, message substring matching | `catch (e) { if (e instanceof TelegramApiError && e.errorCode === 429) e.retryAfter }` | | `EFATAL` | split into `NetworkError` (`EFETCH`) and `TimeoutError` (`ETIMEOUT`) | | `update.message` always `Message \| undefined` | `Update` is a discriminated union - `if ('message' in update) update.message` narrows | | `bot.getMe(...)` etc. (positional + options) | every method takes a single params object: `bot.api.getMe()`, `bot.api.getChat({ chat_id })` | | CommonJS, Node-only | web-standard core (Node 18+, Bun, Deno, Workers, edge); published dual ESM+CJS, so `import` or `require` both work | #### Longer examples
Before (v1) After (v2)

Polling handlers

const TelegramBot = require("node-telegram-bot-api");

const bot = new TelegramBot(process.env.BOT_TOKEN, { polling: true });

bot.onText(/\/start/, (msg) => {
  bot.sendMessage(msg.chat.id, "Hi");
});

bot.onText(/\/echo (.+)/, (msg, match) => {
  bot.sendMessage(msg.chat.id, match[1]);
});

bot.on("callback_query", (query) => {
  bot.answerCallbackQuery(query.id, { text: "ok" });
});

Polling handlers

import { Bot } from "node-telegram-bot-api";
import { run } from "node-telegram-bot-api/node";

const bot = new Bot(process.env.BOT_TOKEN!);

bot.command("start", (ctx) => {
  return ctx.reply("Hi");
});

bot.hears(/\/echo (.+)/, (ctx) => {
  return ctx.reply(ctx.match![1]!);
});

bot.on("callback_query", (ctx) => {
  return ctx.answerCallbackQuery({ text: "ok" });
});

await run(bot);

Uploads

const TelegramBot = require("node-telegram-bot-api");
const fs = require("node:fs");

const bot = new TelegramBot(token);

await bot.sendPhoto(chatId, "./cat.jpg");
await bot.sendDocument(chatId, fs.createReadStream("./report.pdf"));
await bot.sendMediaGroup(chatId, [
  { type: "photo", media: fs.createReadStream("./a.jpg") },
  { type: "photo", media: "https://example.com/b.jpg" },
]);

Uploads

import { Bot, InputFile } from "node-telegram-bot-api";
import { fromPath } from "node-telegram-bot-api/node";
import { readFile } from "node:fs/promises";

const bot = new Bot(token);

await bot.api.sendPhoto({ chat_id: chatId, photo: await fromPath("./cat.jpg") });

const report = await readFile("./report.pdf");
await bot.api.sendDocument({
  chat_id: chatId,
  document: new InputFile(report, { filename: "report.pdf" }),
});

await bot.api.sendMediaGroup({
  chat_id: chatId,
  media: [
    { type: "photo", media: await fromPath("./a.jpg") },
    { type: "photo", media: "https://example.com/b.jpg" },
  ],
});

Proxy request options

const TelegramBot = require("node-telegram-bot-api");
const { ProxyAgent } = require("undici");

const dispatcher = new ProxyAgent("http://127.0.0.1:8080");

const bot = new TelegramBot(token, {
  request: {
    fetchOptions: { dispatcher },
  },
});

Proxy request options

import { fetch as undiciFetch, ProxyAgent, type Dispatcher } from "undici";
import { Bot } from "node-telegram-bot-api";

const dispatcher = new ProxyAgent("http://127.0.0.1:8080");

const bot = new Bot(token, {
  fetch: (url, init) =>
    undiciFetch(url, {
      ...init,
      dispatcher,
    } as RequestInit & { dispatcher: Dispatcher }),
});

await bot.api.getMe();
#### Runtime & module format v2's **source and runtime-agnostic core are ESM / web-standard**, but the **published package is dual-module**: `zshy` emits both an ESM build (`*.js` / `*.d.ts`) and a CommonJS build (`*.cjs` / `*.d.cts`), and the `package.json` `exports` map exposes both `import` and `require` conditions. So unlike v1, the module system is **not** a migration blocker - a CommonJS project can keep calling `require()`: ```js // ESM import { Bot, Api } from "node-telegram-bot-api"; // CommonJS const { Bot, Api } = require("node-telegram-bot-api"); ``` The real break from v1 is the **API surface** (no `TelegramBot` class, single-argument methods, middleware instead of events - see the table above), not the way you load the module. The runtime-agnostic core still imports only web-standard APIs, so it runs unchanged on Node 18+, Bun, Deno, and edge runtimes; the CommonJS build is purely a convenience for Node consumers and pulls no Node dependency into the core. The **package name is intentionally retained** (`node-telegram-bot-api`) even though v2 shares no API surface with v1. This is a deliberate semver-major: the name carries the install base and the docs/SEO, and v2 owns the lineage. The cost is that `npm install node-telegram-bot-api` on an old tutorial now lands you on a completely different API - the version (`^2`) is the only signal, so pin it. #### Mental-model shifts - **One client, single-argument methods.** `Api` mirrors the wire API: one method per Bot API method, each taking one params object. Positional ergonomics (`ctx.reply(text)`) live on `Context`. - **Structured fields are plain typed objects.** `reply_markup`, `entities`, `reply_parameters`, `media`, ... take a plain object/array (or a fluent builder, which returns the same plain shape); the pipeline serializes them once. No `json()` wrapper, no branded strings. A nested file is just an `InputFile` dropped into the file field - the pipeline hoists it to an `attach://` part. - **Composition over events.** `bot.use(mw)` and the filter helpers (`on`/`command`/`hears`) are koa-style middleware over a per-update `Context`, so sessions/auth/rate-limiting/error-boundaries wrap one another via `await next()`. A handler error never stops the bot: it is routed to the error boundary (default: log via `console.error` and continue); install your own with `bot.catch()`, and rethrow from it to opt back into fail-loud. - **Two entry points, one dispatch path.** `bot.startPolling(source)` pumps an async generator for long-running processes; `bot.handleUpdate(update)` handles a single update and is what the edge/webhook callback calls. - **Node helpers are opt-in.** `import ... from 'node-telegram-bot-api'` is the runtime-agnostic core; `import ... from 'node-telegram-bot-api/node'` adds `fromPath`, `createWebhookServer`, and `run`. - **Uploads stream.** Multipart bodies are hand-rolled as a web `ReadableStream` and handed straight to `fetch` (`duplex: "half"`), so file bytes flow from their source without ever being buffered - upload memory stays flat regardless of file size. `fromPath()` wraps the file as a stream factory that re-opens a disk read stream per attempt (`fs.openAsBlob` was rejected: Deno's node-compat implementation buffers the whole file eagerly). `Blob`/`Uint8Array` uploads re-stream on retry; a one-shot `ReadableStream` `InputFile` is sent exactly once and a failure surfaces immediately instead of retrying; a stream factory (`InputFileStreamFactory`, `() => ReadableStream`) opens a fresh stream per attempt and stays retryable. A runtime whose `fetch` cannot stream a request body (Bun < 1.4.0 with an HTTP(S) proxy configured - oven-sh/bun#33918, fixed upstream by oven-sh/bun#32635) transparently sends the same bytes as one buffered `Blob`. `inputFileToBlob` is gone - nothing converts to `FormData` anymore. The default per-request `timeoutMs` is now 300000 (5 min, was 30s) so a large upload on a slow link is not cut off mid-stream. ## [1.1.2][1.1.2] - 2026-06-25 ### Added - **CommonJS consumption restored.** The package now ships a dual ESM + CJS build (produced by `zshy`): the `package.json` `exports` map exposes both an `import` and a `require` condition (with their own `.d.ts` / `.d.cts` typings), so the library can be loaded with either syntax β€” ```js // CommonJS const { TelegramBot } = require("node-telegram-bot-api"); // ESM (unchanged) import TelegramBot from "node-telegram-bot-api"; ``` The v1.0.0 dynamic-import workaround (`const { default: TelegramBot } = await import("node-telegram-bot-api")`) is no longer required. Source maps are emitted for both module formats, and each CJS artifact references its own map. ## [1.1.1][1.1.1] - 2026-06-22 ### Added - `request.fetch` and `request.fetchOptions` options (on the `TelegramBot` constructor / `HttpClient`), for per-instance transport customization. Pass a custom `fetch` implementation (e.g. undici's `fetch` bound to a `ProxyAgent`), or extra fetch init such as an undici `dispatcher`, scoped to a single bot instance - no `setGlobalDispatcher`, so other clients in the process are unaffected. This restores the per-instance proxy capability that the legacy `request.agent` provided before the move to the built-in `fetch`. (#1319) ```ts import TelegramBot from "node-telegram-bot-api"; import { ProxyAgent } from "undici"; const bot = new TelegramBot(token, { polling: true, request: { fetchOptions: { dispatcher: new ProxyAgent("http://127.0.0.1:8080") } }, }); ``` ### Fixed - `editMessageMedia` now accepts a Buffer / stream / local file path for the new `media` (and its `thumbnail` / `cover`), uploading it via an `attach://` part - previously only a file_id / URL or the legacy `attach://` form worked. Resolved through the same `_buildMediaItems` pipeline as `sendMediaGroup`; string callers and the old `attach://` form are unaffected. ([#1189](https://github.com/yagop/node-telegram-bot-api/issues/1189)) - **Breaking:** `createNewStickerSet` and `addStickerToSet` were still sending the long-removed `png_sticker` / `emojis` fields, which Telegram rejects with `400 Bad Request: invalid sticker emojis`. They now use the current Bot API shape - a single options object carrying `stickers: InputSticker[]` (or a single `sticker: InputSticker`), where each sticker's file (Buffer / stream / local path) is uploaded via an `attach://` part, while a file_id / URL string passes through unchanged. ([#1236](https://github.com/yagop/node-telegram-bot-api/issues/1236)) ```ts // Before (broken): bot.createNewStickerSet(userId, name, title, pngSticker, "πŸ˜€"); // After: bot.createNewStickerSet({ user_id: userId, name, title, stickers: [{ sticker: "./a.png", format: "static", emoji_list: ["πŸ˜€"] }], }); bot.addStickerToSet({ user_id: userId, name, sticker: { sticker: "./b.webp", format: "static", emoji_list: ["🎈"] }, }); ``` ## [1.1.0][1.1.0] - 2026-06-13 ### Bot API 10.1 (June 11, 2026) #### Rich Messages - Added the method `sendRichMessage(chatId, richMessage, form?)` β†’ `Message`. - Added the method `sendRichMessageDraft(chatId, draftId, richMessage, form?)` β†’ `boolean`. - Added the parameter `rich_message` to `editMessageText`, alongside a new single-object overload: ```ts // New (preferred) β€” text or rich_message: editMessageText({ chat_id, message_id, text: "…" }) editMessageText({ chat_id, message_id, rich_message: { … } }) // Old (deprecated, still works): editMessageText("text", { chat_id, message_id }) ``` - Added the type `InputRichMessage` (with `html` / `markdown` / `is_rtl` / `skip_entity_detection` fields), which is JSON-serialized automatically. - Regenerated `src/types/schemas.ts` with all new RichMessage, RichText, RichBlock, and related types. #### Join Request Queries - Added the method `answerChatJoinRequestQuery(queryId, result, form?)` β†’ `boolean`. - Added the method `sendChatJoinRequestWebApp(queryId, webAppUrl, form?)` β†’ `boolean`. - Added the fields `supports_join_request_queries` to `User`, `guard_bot` to `ChatFullInfo`, and `query_id` to `ChatJoinRequest` (in the generated types). #### Polls - Added the types `Link` and `InputMediaLink` (generated). ## [1.0.0][1.0.0] - 2026-06-12 ### Rewritten in TypeScript The library has been rewritten from JavaScript to TypeScript and now requires **Node.js β‰₯ 18**. The public surface β€” the `TelegramBot` class, its method names, their positional arguments, and the emitted events β€” is otherwise unchanged, so most bots keep working after the breaking changes below. ### Migrating from v0.67.x - **ESM-only.** The package is `"type": "module"`; `require()` no longer works β€” use `import TelegramBot from "node-telegram-bot-api"`. The class is both the default and a named export. If you are stuck on CommonJS, load it with a dynamic import: `const { default: TelegramBot } = await import("node-telegram-bot-api")`. - **`answerCallbackQuery`** β€” the legacy `answerCallbackQuery(id, text, showAlert)` and `answerCallbackQuery([options])` forms are removed; use `answerCallbackQuery(id, { text, show_alert })`. - **`thumb` β†’ `thumbnail`** on `sendAudio` / `sendDocument` / `sendVideo` / `sendAnimation` / `sendVoice` and the sticker methods. - **`reply_to_message_id` β†’ `reply_parameters`:** `{ reply_parameters: { message_id } }`. - **Reply-keyboard string shorthand removed.** `KeyboardButton` is an object only; use `keyboard: [[{ text: "Yes" }]]` instead of `keyboard: [["Yes"]]`. (`reply_markup` is still serialized for you, or you may pass a pre-stringified value.) - **Error `response` shape.** Errors still expose `code` (`EFATAL` / `EPARSE` / `ETELEGRAM`) and `response`, but `response` is now a plain object, not the raw `http.IncomingMessage`: read `error.response.status` (was `response.statusCode`); `error.response.body` is unchanged. - **`NTBA_FIX_350` removed.** `filename` / `contentType` are always auto-resolved (including magic-byte sniffing of `Buffer`s); override per call via the file-options argument. - **`request` constructor option** still exists but feeds the internal `fetch`-based `HttpClient` (timeouts, default headers) rather than the old `request` library β€” review any proxy/agent configuration. - **Build output** moved from `lib/` to `dist/`. ### Breaking changes for `@types/node-telegram-bot-api` users The bundled types replace the community `@types/node-telegram-bot-api` (DefinitelyTyped) package. Uninstall `@types/node-telegram-bot-api`; the following differences affect existing typed code: - **Types are no longer namespaced.** The old package exposed everything under a `TelegramBot.*` namespace (`TelegramBot.Message`, `TelegramBot.ChatId`, …). Types are now flat named exports β€” replace `TelegramBot.Message` with a named import: `import TelegramBot, { type Message } from "node-telegram-bot-api"`. The default import of the class is unchanged. - **`*Options` interfaces are now `*Params` types.** Per-method option interfaces (`SendMessageOptions`, `SendPhotoOptions`, …) are replaced by docs-faithful `Params` types that include the positional arguments; each method types its trailing argument as `Omit<Params, …>`. There are no aliases under the old names. - **Renamed types:** `ConstructorOptions` β†’ `TelegramBotOptions`, `StartPollingOptions` β†’ `PollingStartOptions`, `StopPollingOptions` β†’ `PollingStopOptions`, `FileOptions` β†’ `FileMeta`, `Metadata` β†’ `EventMetadata`, `TelegramEvents` β†’ `TelegramBotEvents`. `TextListener` / `ReplyListener` are no longer exported. - **`restrictChatMember(chatId, userId, permissions, options?)`** β€” `permissions` is now a required positional argument, not an option field. - **`sendPoll`** β€” `pollOptions` changed from `string[]` to `InputPollOption[]` (`{ text, … }` objects), matching the current Bot API. - **`setStickerSetThumb` β†’ `setStickerSetThumbnail`** (method renamed; adds a `format` option). - **Removed legacy option fields** (the generated params are docs-faithful): `disable_web_page_preview` (use `link_preview_options`), top-level `allow_sending_without_reply` (use `reply_parameters`), and `answerInlineQuery`'s `switch_pm_text` / `switch_pm_parameter` (use `button`). - **Constructor `request` option** is no longer the `request` library's `Options` type β€” the client is `fetch`-based and the dependency is dropped. - **`PollingOptions.interval`** is `number` only (was `string | number`). - Array arguments (`answerInlineQuery` results, `sendMediaGroup` media, `sendInvoice` prices, `setMyCommands` commands) no longer accept `readonly` arrays. ### Added - **TypeScript** β€” full type coverage for all API methods, options, and responses, bundled with the package (no separate `@types/...` install) - **Generated types** β€” `src/types/schemas.ts` is generated from the live Bot API docs (`npm run generate:types`) as plain `type` aliases; the types are docs-faithful and carry no runtime validation - **ESM** β€” the package is now ESM-only (`"type": "module"`); `require()` is no longer supported - `TelegramBotOptions` type exported from the main entrypoint - Type exports: `ChatId`, `ParseMode`, `MessageEntity`, `ReplyMarkup`, `ReplyParameters`, `LinkPreviewOptions`, `SuggestedPostPrice`, `SuggestedPostInfo`, `SuggestedPostParameters`, and all generated API types - Node.js native test runner replaces Mocha - `sendLivePhoto` method ### Changed - `src/telegram.js` β†’ `src/telegram.ts` (full rewrite) - `src/telegramPolling.js` β†’ `src/polling.ts` - `src/telegramWebHook.js` β†’ `src/webhook.ts` - `src/errors.js` β†’ `src/errors.ts` - `src/utils.js` β†’ `src/utils.ts` - `test/` rewritten in TypeScript with `node:test` assertions - Build output: `lib/` β†’ `dist/` ### Removed - CJS support β€” `require('node-telegram-bot-api')` no longer works; use `import` - Mocha test infrastructure (`test/mocha.opts`, legacy `test/telegram.js`) - Legacy `lib/` output directory - Legacy file-option param `thumb` β€” replaced by `thumbnail` - Deprecated request option `reply_to_message_id` β€” use `reply_parameters` - Legacy `answerCallbackQuery(id, text, showAlert)` / `answerCallbackQuery([options])` signatures β€” use `answerCallbackQuery(id, options)` - `NTBA_FIX_350` environment flag β€” `filename`/`contentType` are now always auto-resolved ### Fixed - String errors now include timestamps in console output ## [0.68.0][0.68.0] - 2026-04-05 Added: 1. Support Telegram Bot API v9.3 (by @danielperez9430) * `#getUserGifts` * `#getChatGifts` * `#sendMessageDraft` (by @xjx0106) * `#repostStory` 2. Fixed method: * `unpinAllGeneralForumTopicMessages` * `replaceStickerInSet` 3. Support Telegram Bot API v9.5 (by @danielperez9430) * `setChatMemberTag` 4. Support Telegram Bot API v9.6 (by @danielperez9430) * setMyProfilePhoto * removeMyProfilePhoto 5. Added missing methods (by @danielperez9430) * getUserProfileAudios * approveSuggestedPost * declineSuggestedPost 6. Added more test 7. Support Telegram Bot API v9.6 * getManagedBotToken * replaceManagedBotToken * savePreparedKeyboardButton ## [0.67.0][0.67.0] - 2025-12-13 Added: 1. Support Telegram Bot API v7.4 (by @danielperez9430) * `#refundStarPayment` 6. Support Telegram Bot API 7.6 (@danielperez9430) * `#sendPaidMedia` 1. Support Telegram Bot API v7.9 (by @danielperez9430) 1. Support Telegram Bot API v7.10 (by @danielperez9430) * Update: `purchased_paid_media` 1. Support Telegram Bot API v8.0 and v8.1 * `#savePreparedInlineMessage` (@IsmailBinMujeeb) * `#setUserEmojiStatus` (@danielperez9430) * `#editUserStarSubscription` (@danielperez9430) * `#getAvailableGifts` (@danielperez9430) * `#sendGift` (@danielperez9430) 1. Support Telegram Bot API v8.2, v8.3 (@danielperez9430) * `#verifyUser` * `#verifyChat` * `#removeUserVerification` * `#removeChatVerification` 1. Support Telegram Bot API v8.3 (by @danielperez9430) 1. Support Telegram Bot API v9.0 (by @danielperez9430) * `#readBusinessMessage` * `#deleteBusinessMessages` * `#setBusinessAccountName` * `#setBusinessAccountUsername` * `#setBusinessAccountBio` * `#setBusinessAccountProfilePhoto` * `#removeBusinessAccountProfilePhoto` * `#setBusinessAccountGiftSettings` * `#getBusinessAccountStarBalance` * `#transferBusinessAccountStars` * `#getBusinessAccountGifts` * `#convertGiftToStars` * `#upgradeGift` * `#transferGift` * `#postStory` * `#editStory` * `#deleteStory` * `#giftPremiumSubscription` 1. Support Telegram Bot API v9.1 (by @danielperez9430) * `#sendChecklist` * `#editMessageChecklist` * `#getMyStarBalance` Fixed: 1. Reference causing error in `FatalError` (by @ivanjh) 1. Stringify `scope` field in `#deleteMyCommands` (by @XC-Zhang) 1. Stringify `allowed_updates` field in `#getUpdates` (by @alfanzain) 1. Stringify `message_ids` in `#forwardMessages` (by @qiaoshouzi) 1. Rename parameter `thumb` to `thumbnail` (by @0x114514BB) 1. Remove travis badge (by @melroy89) 1. Improve documentation on events (by @programminghoch10) 1. Fix Telegram invite group link (by @melroy89) ## [0.66.0][0.66.0] - 2024-05-03 1. Support Telegram Bot API 7.2 & 7.3 (@danielperez9430) * getBusinessConnection * replaceStickerInSet 2. Support for updates: (@danielperez9430) * business_connection * business_message * edited_business_message * deleted_business_messages 3. Minor fixes: (@danielperez9430) * getUserChatBoosts ## [0.65.1][0.65.1] - 2024-03-09 1. Support for updates (@danielperez9430) * message_reaction * message_reaction_count * chat_boost * removed_chat_boost ## [0.65.0][0.65.0] - 2024-02-20 1. Support Telegram Bot API v7.1 * deleteMessages (@Sp3ricka) * copyMessages (@xjx0106 & @Sp3ricka) * setMessageReaction (@Sp3ricka) * forwardMessages (@danielperez9430) * getUserChatBoosts (@danielperez9430) 2. Minor changes: (@danielperez9430) * Refactor methods order * Fix copyMessages & setMessageReaction methods * Added missing tests * Fix tests for methods copyMessages & getMyDefaulAdministratorRights ## [0.64.0][0.64.0] - 2023-10-25 1. Replace `request` with a maintained version (@danielperez9430) * Change `request` to `@cypress/request` * Change `request-promise` to `@cypress/request-promise` ## [0.63.0][0.63.0] - 2023-08-23 1. Support Telegram Bot API v6.8 (@danielperez9430) * unpinAllGeneralForumTopicMessages ## [0.62.0][0.62.0] - 2023-03-19 1. Support Telegram Bot API v6.6 & v6.7 (@danielperez9430) * setMyDescription * getMyDescription * setMyShortDescription * getMyShortDescription * setCustomEmojiStickerSetThumbnail * setStickerSetTitle * deleteStickerSet * setStickerEmojiList * setStickerKeywords * setStickerMaskPosition ## [0.61.0][0.61.0] - 2022-12-30 1. Support Telegram Bot API v6.4 (@danielperez9430) * editGeneralForumTopic * closeGeneralForumTopic * reopenGeneralForumTopic * hideGeneralForumTopic * unhideGeneralForumTopic 2. Minor changes: (@danielperez9430) * The parameters `name` and `icon_custom_emoji_id` of the method `editForumTopic` are now optional. * Fix add thumb in sendAudio, sendVideo and sendVideoNote * Fix getMyCommands and setMyCommands * Suggested tip amounts stringify in sendInvoice ## [0.60.0][0.60.0] - 2022-10-06 1. Support Telegram Bot API v6.3 (@danielperez9430) * createForumTopic * closeForumTopic * reopenForumTopic * deleteForumTopic * unpinAllForumTopicMessages * getForumTopicIconStickers 2. Fix test getMyDefaultAdministratorRights (@danielperez9430) 3. Fix parse entities - (@toniop99) ## [0.59.0][0.59.0] - 2022-08-15 1. Support Telegram Bot API v6.2 (@danielperez9430) * getCustomEmojiStickers 2. Support test enviroment (@tinsaeDev & @kamikazechaser) 3. Remove dependencies: (@danielperez9430) * Remove *bluebird* => Use NodeJS Native Promises * Remove *depd* => Use node native deprecate util for warnings * Remove contributor dev dependency and add list of contributors in the readme 4. Remove legacy methods: (@danielperez9430) * getChatMembersCount * kickChatMember 5. Docs: (@danielperez9430) * Update the docs of the methods * Order methods follow the Telegram bot API docs in src/telegram.js * Update README 6. Fix: (@danielperez9430) * addStickerToSet() -> Allow to send tgs_sticker + webm_sticker * Remove mandatory param β€œstart_parameter” from sendInvoice, because in the docs is a optional param * getStickerSet test fix deprecated response value "contains_masks" change to "sticker_type" * Fix some other tests 7. New Test: (@danielperez9430) * deleteStickerFromSet * setStickerPositionInSet * getCustomEmojiStickers ## [0.58.0][0.58.0] - 2022-06-22 1. Support Bot API v6.1: (@danielperez9430) * Add method *createInvoiceLink()* 2. Support for setStickerSetThumb (@elihaidv) 3. Add new test (@danielperez9430) * createInvoiceLink 4. Test fixes (@danielperez9430) * sendVideoNote * createNewStickerSet * setStickerSetThumb * getChatMenuButton * setWebHook 5. Bug fixes (@danielperez9430) * answerWebAppQuery * Support for send thumb in sendAudio ## [0.57.0][0.57.0] - 2022-04-23 Added: 1. Support Bot API v6: (@danielperez9430) * Add method *setChatMenuButton()* * Add method *getChatMenuButton()* * Add method *setMyDefaultAdministratorRights()* * Add method *getMyDefaultAdministratorRights()* * Add method *answerWebAppQuery()* * Renamed the fields voice_chat_scheduled, voice_chat_started, voice_chat_ended, and voice_chat_participants_invited to video_chat_scheduled, video_chat_started, video_chat_ended, and video_chat_participants_invited Tests: * answerWebAppQuery * setChatMenuButton * getChatMenuButton * setMyDefaultAdministratorRights * getMyDefaultAdministratorRights ## [0.56.0][0.56.0] - 2021-12-07 Added: 1. Support Bot API v5.5: (@danielperez9430) * Add method *banChatSenderChat()* * Add method *unbanChatSenderChat()* Fixes: * Tests for support with new invite link format ## [0.55.0][0.55.0] - 2021-11-06 Added: 1. Support Bot API v5.4: (@danielperez9430) * Add method *approveChatJoinRequest()* * Add method *declineChatJoinRequest()* * Add support for new updates: * *chat_join_request* Fixes: * Method *editMessageMedia*: Now you can send a local file (`"attach://" + filePatch`) ## [0.54.0][0.54.0] - 2021-06-29 Added: 1. Support Bot API v5.3: (@danielperez9430) * Add method *deleteMyCommands()* * Add method *banChatMember()* * Add method *getChatMemberCount()* New Test: * deleteMyCommands * banChatMember * getChatMemberCount Deprecated: * Method *kickChatMember()* * Method *getChatMembersCount()* ## [0.53.0][0.53.0] - 2021-04-26 Added: 1. Support Bot API v5.2:(@danielperez9430) * Add support for new messageTypes: * *voice_chat_scheduled* ## [0.52.0][0.52.0] - 2021-03-20 Added: 1. Support Bot API v5.1: (by @danielperez9430) * Add method *createChatInviteLink()* * Add method *editChatInviteLink()* * Add method *revokeChatInviteLink()* * Add support for new messageTypes: * *voice_chat_started* * *voice_chat_ended* * *voice_chat_participants_invited* * *message_auto_delete_timer_changed* * *chat_invite_link* * *chat_member_updated* * Add support for new updates: * *my_chat_member* * *chat_member* New Test: (by @danielperez9430) * createChatInviteLink * editChatInviteLink * revokeChatInviteLink ## [0.51.0][0.51.0] - 2020-11-04 Added: 1. Support Bot API v5.0: (by @danielperez9430) * Add method *copyMessage()* * Add method *unpinAllChatMessages()* * Add method *close()* * Add method *logOut()* Changed: (by @danielperez9430) * Remove trailing-spaces * Fix Bugs in Test New Test: (by @danielperez9430) * copyMessage * unpinAllChatMessages ## [0.50.0][0.50.0] - 2020-05-2020 Added: 1. Support Bot API v4.8: (by @danielperez9430) * Add methods: *sendDice()* 2. Support Bot API v4.7: (by @danielperez9430) * Add methods: *getMyCommands()*,*setMyCommands()* 3. Support Bot API v4.5: (by @danielperez9430) * Add methods: *setChatAdministratorCustomTitle()* 4. Support Bot API v4.4: (by @danielperez9430) * Add methods: *setChatPermissions()* 5. Support for poll_answer (by @JieJiSS) 6. Add request options in file stream (by @zhangpanyi ) Changed: (by @danielperez9430) * New message type: *dice* * Fix Bugs in tests * Fix regex compare (by @ledamint) * Fix listening for error events when downloading files (by @Kraigo) New Test: (by @danielperez9430) * sendDice * getMyCommands * setMyCommands * setChatAdministratorCustomTitle * setChatPermissions ## [0.40.0][0.40.0] - 2019-05-04 Added: 1. Support Bot API v4.2: (by @kamikazechaser) * Add methods: *TelegramBot#sendPoll()*, *TelegramBot#stopPoll()* * Support events: *poll* 2. Support Bot API v4.0: (by @kamikazechaser) * Add methods: *TelegramBot#editMessageMedia()*, *TelegramBot#sendAnimation()* * Support new message types: *passport_data*, *animation* * * * ## [0.30.0][0.30.0] - 2017-12-21 Added: 1. Support Bot API v3.5: (by @GochoMugo) * Allow `provider_data` parameter in *TelegramBot#sendInvoice* * Add method *TelegramBot#sendMediaGroup()* 2. Support Bot API v3.4: (by @kamikazechaser) * Add methods *TelegramBot#editMessageLiveLocation*, *TelegramBot#stopMessageLiveLocation* (#439) * Add methods *TelegramBot#setChatStickerSet*, *TelegramBot#deleteChatStickerSet* (#440) 3. Add methods: * *TelegramBot#getFileStream* (#442) (by @GochoMugo, requested-by @Xaqron) 4. Add options to *TelegramBot#stopPolling()* (by @GochoMugo) 5. Add `metadata` argument in `message` event (and friends e.g. `text`, `audio`, etc.) (#409) (by @jlsjonas, @GochoMugo) 6. Add forward-compatibility i.e. support future additional Telegram options (by @GochoMugo) 7. Add support for Node.js v9 (by @GochoMugo) 8. Document *TelegramBot.errors*, *TelegramBot.messageTypes* (by @GochoMugo) Changed: 1. Update *TelegramBot#answerCallbackQuery()* signature (by @GochoMugo) 2. Improve default error logging of `polling_error` and `webhook_error` (#377) 3. Update dependencies Deprecated: 1. Sending files: *(See [usage guide][usage-sending-files])* (by @hufan-akari, @GochoMugo) * Error will **not** be thrown if `Buffer` is used and file-type could **not** be detected. * Filename will **not** be set to `data.${ext}` if `Buffer` is used * Content type will **not** default to `null` or `undefined` Fixed: 1. Fix the offset infinite loop bug (#265, #36) (by @GochoMugo) 2. Fix game example (#449, #418) (by @MCSH) * * * ## [0.29.0][0.29.0] - 2017-10-22 Added: 1. Add Bot API v3.2 methods: * (#429) *TelegramBot#getStickerSet* (by @CapacitorSet, @LibertyLocked) * (#430) *TelegramBot#uploadStickerFile* (by @CapacitorSet) * *TelegramBot#createNewStickerSet*, *TelegramBot#addStickerToSet*, *TelegramBot#setStickerPositionInSet*, *TelegramBot#deleteStickerFromSet* (by @GochoMugo) 2. Supports API v3.3 Deprecated: 1. Auto-enabling Promise cancellation (#319) (by @GochoMugo) * * * ## [0.28.0][0.28.0] - 2017-08-06 Added: 1. (#361) Support Bot API v3.1 (by @Lord-Protector, @kamikazechaser) 2. (#332) Support Bot API v3.0 (by @kamikazechaser, @GochoMugo) 3. Add *TelegramBot#removeTextListener()* (by @GochoMugo) 4. (#342) Add game example (by @MCSH) 5. (#315) List 'bot-brother' project in community section in README (by @saeedhei) Changed: 1. (#367) Update *TelegramBot#answerCallbackQuery()* signature (by @mnb3000) Fixed: 1. (#325) Fix global regexp state reset (by @Sirius-A) 2. (#363) Fix download file path on windows (by @kucherenkovova) 3. (#346) Fix anchor webhook link in docs (by @Coac) * * * ## [0.27.1][0.27.1] - 2017-04-07 Added: 1. (#287) Add Express WebHook example (by @kamikazechaser) Fixed: 1. (#291) Improve docs (by @preco21) 2. (#298) Fix running on Node v5 (by @jehy) 3. (#307) Fix badge links in README (by @JaakkoLipsanen) 4. Fix defaulting value of `options.polling.params.timeout` (by @GochoMugo) 5. Fix typos in Github issue template (by @GochoMugo, requested-by @GingerPlusPlus) * * * ## [0.27.0][0.27.0] - 2017-02-10 Added: 1. Add constructor options: * (#243) `options.polling.params` (by @GochoMugo, requested-by @sidelux) 2. Add methods: * (#74) *TelegramBot#removeReplyListener()* (by @githugger) 3. (#283) Add proper error handling (by @GochoMugo) 4. (#272) Add health-check endpoint (by @mironov) * `options.webHook.healthEndpoint` 5. (#152) Add test for TelegramBot#sendDocument() using 'fileOpts' param (by @evolun) 6. Document `options.webHook.host` (by @GochoMugo) 7. (#264) Add Bot API version to README (by @kamikazechaser) 8. Add examples: - (#271) WebHook on Heroku (by @TheBeastOfCaerbannog) - (#274) WebHook on Zeit Now (by @Ferrari) Changed: 1. (#147) Use *String#indexOf()*, instead of *RegExp#test()*, to find token in webhook request (by @AVVS) Fixed: * Fix bug: - (#275, #280) fix es6 syntax error on Node.js v4.x (by @crazyabdul) - (#276) promise.warning from `request-promise` (by @GochoMugo, reported-by @preco21) - (#281) fix handling error during polling (by @GochoMugo, reported-by @dimawebmaker) - (#284) fix error during deletion of already-set webhook, during polling (by @GochoMugo, reported-by @dcparga) 1. Fix links in documentation (by @Ni2c2k) * * * ## [0.26.0][0.26.0] - 2017-01-20 Added: 1. Add *TelegramBot* constructor options: * `options.https` * `options.baseApiUrl` * `options.filepath` 2. Add methods: * *TelegramBot#stopPolling()* * *TelegramBot#isPolling()* * *TelegramBot#openWebHook()* * *TelegramBot#closeWebHook()* * *TelegramBot#hasOpenWebHook()* * *TelegramBot#deleteWebHook()* * *TelegramBot#getWebHookInfo()* Changed: 1. Use POST requests by default 2. Ensure all relevant methods return Promises 3. Document auto-deletion of webhook during polling 4. Deprecate support for Node.js v0.12 5. Fix consistency of methods signatures 6. Rename *TelegramBot#initPolling()* to *TelegramBot#startPolling()* * Deprecate *TelegramBot#initPolling()* Fixed: 1. Handle error during formatting `formData` 2. Fix ES6 syntax *Credits/Blames: Unless explicitly stated otherwise, above work was done by @GochoMugo* * * * ## [0.25.0][0.25.0] - 2016-12-21 Added: 1. Supports the API v2.3 updates (by @kamikazechaser) 2. Add *TelegramBot* constructor option: * `options.request`: proxy extra request options (by @tarmolov) * `options.onlyFirstMatch` (by @GingerPlusPlus) 3. Add methods: * *TelegramBot#sendVenue()* (by Tketa) * *TelegramBot#sendContact()* (by @GochoMugo) * *TelegramBot#getGameHighScores()* (by @jishnu7) Fixed: 1. Fix request performance issue (by @preco21) 2. Fix typos (by oflisback) [usage-sending-files]:https://github.com/yagop/node-telegram-bot-api/blob/master/doc/usage.md#sending-files-options [0.25.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.25.0 [0.26.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.26.0 [0.27.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.27.0 [0.27.1]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.27.1 [0.28.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.28.0 [0.29.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.29.0 [0.30.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.30.0 [0.63.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.63.0 [0.64.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.64.0 [0.65.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.65.0 [0.65.1]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.65.1 [0.66.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.66.0 [0.67.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.67.0 [0.68.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v0.68.0 [1.0.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v1.0.0 [1.1.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v1.1.0 [1.1.1]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v1.1.1 [1.1.2]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v1.1.2 [2.0.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v2.0.0 [2.1.0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v2.1.0 [2.2.0-rc0]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v2.2.0-rc0 [2.2.0-rc1]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v2.2.0-rc1 [2.2.0-rc2]:https://github.com/yagop/node-telegram-bot-api/releases/tag/v2.2.0-rc2 [Unreleased]:https://github.com/yagop/node-telegram-bot-api/compare/v2.2.0-rc2...master