Full reference guide for TBL (Tele Bot Lang)
TBL (Tele Bot Lang) is a lightweight scripting language designed specifically for Telegram bot development. It provides a JavaScript-inspired syntax with built-in functions for rapid bot creation, without the overhead of external dependencies.
await, Promise are validThis section explains the basic steps to create and test your first Telegram bot using TBL.
/newbot to create a new bot.bot).const botToken = "123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ";
Create a /start command for user onboarding:
Bot.sendMessage("Hello " + user.first_name + "! Welcome to my bot.")
Example: /help command:
Bot.sendMessage("Available commands:\n/start - Start bot\n/help - Show help")
The latest TBL update introduces major new features for developers, giving more control, flexibility, and integration possibilities. Here’s a breakdown of everything new:
TBL now supports Webhook mode. You can call bot commands directly using HTTP requests — perfect for building websites, dashboards, or automation tools that interact with your bot in real-time.
Bot.read() MethodA new method Bot.read("/command") allows you to read another command’s source code as a string.
It’s ideal for dynamic command management, code previews, or admin tools.
// Example usage
let code = Bot.read("/start")
Bot.sendMessage("Here's the code for /start:\n" + code)
Use case: Create AI code analyzers, AI chatbot or documentation systems inside your bot.
TBL’s sandbox now supports the safe version of Node.js’s Buffer class. You can process binary data, files, and base64 strings directly in your commands.
// Example
let buf = Buffer.from("TBL Rocks!")
Bot.sendMessage("Buffer length: " + buf.length)
Use case: Work with files, encodings, and binary data safely inside the TBL VM.
Bot.runCommand()Bot.runCommand() has been improved — it now runs inside any update type (messages, callbacks, inline queries, webhooks, etc.).
Previously, it only worked with message updates.
// Works everywhere now
Bot.runCommand("/start")
Use case: Trigger other commands programmatically — regardless of where the update originated.
TBL now supports Dynamic Commands — allowing any update type to have its own handler in the form /handle_{type}.
For example, when a user joins a group, TBL automatically runs /handle_new_chat_member if it exists.
/*Command: /handle_new_chat_member*/
Bot.sendMessage("👋 Welcome " + user.first_name + "!")
This applies to all non-message updates like chat_member, poll_answer, message_reaction, etc.
/handle_chat_member → runs when user status changes/handle_poll_answer → runs on poll responses/handle_message_reaction → runs on new reactions/handle_chat_boost → runs on chat boost updatesSpecial Commands like /inline_query and /channel_update are still supported and prioritized.
/handle_{type} pattern.Commands are the core building blocks of TBL. Instead of using event listeners like bot.on(), TBL follows a command-driven model.
Each command acts like a rule: when the trigger matches, the bot runs its script.
A command can include these parts:
/start, hi, /help)/startWelcome! Choose an option:Help, About\nContactBot.sendMessage("Hello " + user.first_name + "!")
In this example:
/start triggers the commandAnswers are quick static messages. They appear before any code runs.
/*Command: /help
answer: I can do these things:
- /start → Start the bot
- /about → Info about me*/
Bot.sendMessage("Extra help details...")
If need_reply is set to true, the bot waits for the next user message before continuing.
/*command: /ask
answer: What is your favorite color?
need_reply: true*/
Bot.sendMessage("You answered: " + message)
Aliases let one command have multiple triggers.
/*Command: /hello
aliases: hi, hey, hola*/
Bot.sendMessage("Hello there!")
Commands can show custom keyboards:
Yes,No\n → Yes\nNo/*Command: /menu
answer: Choose an option:
keyboard: Yes,No\nMaybe*/
Bot.sendMessage("Waiting for your choice...")
TBL provides special system-level commands:
**TBL now supports dynamic command handlers for every Telegram update type.
Any update (other than messages) can be handled automatically by creating a command following this pattern:
/handle_{update_type} → will be executed for that specific update type.For example:
/*Command: /handle_chat_member*/
Bot.sendMessage("A chat member update occurred!")
This feature works for all update types listed in the Telegram Bot API, including:
my_chat_memberchat_memberchat_join_requestbusiness_messageedited_business_messagepollpoll_answermessage_reactionmessage_reaction_countchat_boostremoved_chat_boostIf a /handle_{update_type} command is not defined, the update will fall back to /channel_update (for channel-related updates) or * as a universal fallback.
Handles inline mode queries (when users type @yourbot query in Telegram).
Command: /inline_query
Bot.sendMessage("You searched: " + request.query)
Handles channel posts automatically.
Command: /channel_update
Bot.sendMessage("New channel post received!")
/buy_ticket, not /cmd69/handle_{type} for any special update typeawaitTBL provides a set of predefined global variables. These are available in every command, so you don’t need to declare them manually. They make it easier to work with Telegram updates, users, chats, and the bot itself.
The raw Telegram update object. Contains everything Telegram sends (messages, edits, queries, etc.).
{
"update_id": 109608973,
"message": {
"message_id": 17261,
"from": {
"id": 5723455420,
"is_bot": false,
"first_name": "Soumyadeep ∞",
"username": "soumyadeepdas765",
"language_code": "en",
"is_premium": true
},
"chat": {
"id": 5723455420,
"first_name": "Soumyadeep ∞",
"username": "soumyadeepdas765",
"type": "private"
},
"date": 1758100437,
"text": "/start",
"entities": [
{
"offset": 0,
"length": 6,
"type": "bot_command"
}
]
}
}
Simplified version of update. TBL automatically detects the type of update. like when the update type is message then request will be update.message
And in Webhook request object contains info like ip, body, params, header etc..
Contains only the text of a message (if applicable).
"Hello bot"
Information about the user interacting with the bot.
{
"id": 5723455420,
"is_bot": false,
"first_name": "Soumyadeep ∞",
"username": "soumyadeepdas765",
"language_code": "en",
"is_premium": true,
"last_name": "",
"telegramid": 5723455420,
"premium": true,
"blocked": false,
"block_reason": null,
"blocked_at": null
}
Details about the current chat (private, group, or channel).
{
"id": 5723455420,
"first_name": "Soumyadeep ∞",
"username": "soumyadeepdas765",
"type": "private",
"chatid": 5723455420,
"chatId": 5723455420,
"blocked": false,
"block_reason": null,
"blocked_at": null
}
Information about the bot including owner, status, and platform info.
{
"id": 42, // bot id in our platform , a unique identifier for each bot
"token": "123456:ABC...",
"name": "DemoBot",
"bot_id": 987654321, // Bot actual Telegram id
"owner": "somemail@telebothost.com",//bot owner mail
"status": "working",
"created_at": "2025-01-01",
"updated_at": "2025-01-10",
"_securityNote": "All bot tokens are securely encrypted in storage and during transmission.",
"_fairUseNote": "Usage must comply with policies. Harmful or unfair use may result in a ban."
}
Extra text after a command. Example: "/start hello" → params = "hello".
"hello"
Custom data passed between commands when chaining or using API callbacks.
//passing custom
{
"name": "Alice",
"step": 2
}
//when callback of Telegram Api call
{
"ok": true,
"result": {...}
}
Contains the response body from an HTTP request.
Helper function to print any object for debugging.
like if you did inspect(data) it will return bot Details
msg is a simplified version of update. It’s only available for message updates.
Whenever a message update is received, msg will contain the same object as update.message.
It's a object that gives information about error got by ! command
TBL provides several predefined classes. These classes give you direct access
to Telegram features, user data, and external utilities.
The most important one is Api, which works as a direct wrapper
for the official Telegram Bot API.
The Api class lets you call any Telegram method.
You can use it directly, with callbacks, async/await, or with chained message methods.
sendMessage or sendmessage.
The simplest way to use Api is to call a method directly.
No await is needed. The message will be sent in the background.
// Send a simple message
Api.sendMessage({ text: "Hello user!" })
// Send a photo
Api.sendPhoto({ photo: "https://example.com/cat.jpg", caption: "Cute cat" })
on_run Callback
You can pass on_run to any Api call to run another command when the call finishes.
Useful if you want to continue logic in a separate command.
// Get bot info and continue in another command
Api.getMe({ on_run: "afterGetMe" })
// Inside "afterGetMe" command
if (options.ok) {
Api.sendMessage({ text: "Bot username: @" + options.result.username })
}
For sequential logic, you can use async/await.
This lets you store results in variables and act on them immediately.
let me = await Api.getMe()
if (me.ok) {
Api.sendMessage({ text: "My bot id is " + me.result.id })
}
let sent = await Api.sendMessage({ text: "Hello again!" })
Bot.inspect(sent) // Full Telegram response
Every response object returned from Bot.sendMessage(), Api.sendMessage(), etc. now supports chained methods.
These let you quickly react, edit, reply, pin, forward, or delete the message.
// Send a message and chain methods
let data = await Api.sendMessage({text: "Hello user!"})
await data.pin() // Pin the message
await data.react("👍") // Add reaction
await data.editText("Updated text") // Edit message text
await data.reply("Replied Message") // Reply to message
dn → disable notification
The Bot class is used for controlling your bot directly.
It provides methods for running commands, sending messages, and managing persistent bot-level properties.
Unlike Api, the Bot methods are designed to be easier to use inside commands.
The following methods are available in the Bot class:
You can tell the bot to run another command. This is useful if you want to move the user to a new flow. These methods don’t return any value – they just execute the command.
// Run another command
Bot.runCommand("/start")
// Run with options
Bot.runCommand("/start", { key: 111 })
// key is available now in /start and accessible with options.key
await Bot.run("/cmd") will throw, but Bot.run("/cmd") will silently fail.
The Bot.read() method lets you read the raw code of another command as a string.
It does not return any metadata like answer, keyboard, or need_reply.
Useful for dynamically inspecting or reusing command logic.
// Read the raw code of a command
let code = Bot.read("/start")
// Display or use the command code
Bot.sendMessage(code)
These methods send messages or media to the current chat.
They return the Telegram API response.
Using await is optional – you can wait for the result or just send without waiting.
With await it's support Api Chained method too
// Send plain text
Bot.sendMessage("Hello user!")
// Send with HTML formatting
let res = await Bot.sendMessage("Hello friend", { parse_mode: "html" })
Bot.inspect(res) // See the Telegram response
// Send with a keyboard
Bot.sendKeyboard("Choose an option:", "Yes,No")
// Send files
Bot.sendDocument("file.pdf", { caption: "Here is your file" })
Bot.sendPhoto("photo.jpg", { caption: "Nice view!" })
Bot.sendAudio("music.mp3", { performer: "Artist", title: "Track" })
Bot.sendVideo("video.mp4", { caption: "Watch this" })
Bot.sendVoice("voice.ogg")
// Debugging an object
Bot.inspect({ user: "Alice", id: 123 })
//chain example
let data =await Bot.sendMessage("pinned message")
data.pin()//pin the previous message
Bot properties are simple key-value storage.
They let you save data that belongs to the bot itself (not a specific user).
All property methods are synchronous, so await is not required.
// Set properties
Bot.set("version", "1.2.3", "String")
Bot.set("config", { apiKey: "xyz" }, "Json")
// Get values
let v = Bot.get("version") // "1.2.3"
let c = Bot.get("config") // { apiKey: "xyz" }
// Delete one property
Bot.del("version")
// Get all properties
let all = Bot.getAll()
// Delete all
Bot.delAll()
// Check if a property exists
let has = Bot.has("config") // true
// Count all properties
let count = Bot.count() // e.g. 1
// Get all property names
let names = Bot.getNames() // ["config"]
The following data types are supported when storing bot properties:
type parameter is optional in Bot.set().
If not provided, the type is automatically detected.All property methods have short aliases. They work exactly the same, just different names.
// Setting values
Bot.setProp("theme", "dark", "String")
Bot.setProperty("lang", "en", "String")
// Getting values
Bot.getProp("theme") // "dark"
Bot.getProperty("lang") // "en"
// Deleting values
Bot.delProp("theme")
Bot.delProperty("lang")
// Get all / delete all
Bot.getAllProp()
Bot.getAllProperty()
Bot.delAllProp()
Bot.delAllProperty()
// Checking and counting
Bot.hasProp("theme")
Bot.countProps()
Bot.getPropNames()
The HTTP class allows your bot to make external API requests (GET, POST, etc.) and handle responses flexibly.
It supports direct calls with await, chaining commands for success/error handling.
Simple GET request:
// GET request using direct URL
let data = await HTTP.get("https://jsonplaceholder.typicode.com/todos/1")
Bot.inspect(data)
// we will have data.content(raw string ), data.headers, data.cookies, data.data(parsed)
/* Demo data
{
ok: true,
status: 200,
statusText: 'OK',
content: '{"ok":true,"ping":true}', //content is String
data: {
ok: true,
ping: true
}, // if it JSON then auto parsed
headers: {
'content-type': 'application/json; charset=utf-8'
...more
},
cookies: []
}
*/
// GET request using object with options
let data2 = await HTTP.get({
url: "https://jsonplaceholder.typicode.com/todos/2",
headers: { "Authorization": "Bearer ABC123" }
})
Bot.inspect(data2)
POST request example:
// POST request
let payload = { name: "Alice", age: 25 }
let response = await HTTP.post({
url: "https://jsonplaceholder.typicode.com/posts",
body: payload,
headers: { "Authorization": "Bearer ABC123" }
})
Bot.inspect(response)
tbl_options
You can define commands to run automatically on success or error.
If error command is missing, the success command will run instead.
// HTTP GET with success/error commands
HTTP.get({
url: "https://jsonplaceholder.typicode.com/todos/1",
success: "onSuccess",
error: "onError",
tbl_options: {key : value} //optinal for passing custom values only
})
// you can get tbl_options on next command like
tbl_options.key
// "onSuccess" command will receive options = HTTP response
// "onError" command will receive options = HTTP error
// on success you will get content and in error command you will get error
// error command only run when there an internal error like request failed due to some reasons like
// wrong url, API have 500 etc...
//
// Example success command
/*command: onSuccess*/
Bot.sendMessage("Fetched title: " + content)
// Example error command
/*command: onError*/
Bot.sendMessage("HTTP request failed: " + error.status)
// GET with query params and headers, and success/error commands
HTTP.get({
url: "https://api.example.com/search",
query: { q: "telebot", limit: 5 },
headers: { "X-Api-Key": "123ABC" },
timeout: 5000,
success: "searchSuccess",
error: "searchError"
})
response object on callback command: { ok, status, data or error }.await to wait for the response or skip it if not needed.error command is missing, the success command will run instead.The User class is used to store and manage data for each user individually. Every user has their own private storage, and these methods let you save, read, and delete that data.
Use these methods to save and read single values for the current user.
// Save user data
User.set("name", "Alice")
User.set("age", 25, "number")
// Read user data
let name = User.get("name") // "Alice"
let age = User.getProp("age") // 25
Bot.sendMessage("Name: " + name + ", Age: " + age)
// → Name: Alice, Age: 25
Remove specific values when you don’t need them anymore.
If the property doesn’t exist, it just returns null when read.
// Delete property
User.del("age")
let age = User.get("age") // null
Bot.sendMessage("After delete, age = " + age)
// → After delete, age = null
You can work with all stored data at once. This is useful to inspect or reset the user’s storage.
// Save multiple values
User.set("country", "India")
User.set("verified", true, "boolean")
// Get all user data
let all = User.getAll()
Bot.inspect(all)
// → { "name": "Alice", "country": "India", "verified": true }
// Delete all properties
User.delAll()
let all2 = User.getAll()
Bot.inspect(all2)
// → {}
Check if data exists, count stored keys, or list property names.
// Check if property exists
let hasName = User.has("name") // true or false
// Count total properties
let total = User.count() // e.g. 2
// Get property names
let names = User.getNames() // ["name", "country"]
Bot.inspect({ hasName, total, names })
// → { "hasName": true, "total": 2, "names": ["name", "country"] }
get, set, and del have multiple aliases (like getProp, getProperty).await — they just return undefined.
The Webhook class is used to generate secure URLs for your bot’s webhook endpoints.
These URLs can trigger bot commands directly from external sources — like web pages, APIs, or user dashboards —
while keeping data protected with cryptographic signatures.
Global webhooks are public endpoints anyone can access. Ideal for open integrations, landing pages, or APIs that don’t require authentication.
Webhook.getGlobalUrl()User-based webhooks are tied to a specific user and contain a secure signature for that user. Perfect for personalized dashboards, user actions, or account-specific operations.
Webhook.getUrl() or Webhook.getUrlFor()getUrl(command, { options, params, redirect })Generates a secure user-based webhook for the current user. You can include optional parameters and redirect URLs.
let syncUrl = Webhook.getUrl("syncGameData", {
options: { level: 10 },
params: { ref: "profile", lang: "en" }
})
Api.sendMessage({
text: `Sync your game data: ${syncUrl}`
})
getUrlFor({ user_id, command, options, params, redirect })Generates a webhook for a specific user. Ideal for sending personalized links or actions to a given user ID.
let upgradeUrl = Webhook.getUrlFor({
user_id: 123,
command: "syncGameData",
redirect: "https://telebothost.com",
options: { plan: "pro" },
params: { ref: "upgrade" }
})
Api.sendMessage({
text: `Upgrade your plan here: ${upgradeUrl}`
})
getGlobalUrl(command, { options, params, redirect })Creates a globally accessible webhook URL that does not require user authentication. You can attach query parameters or redirect links for external flows.
let statsUrl = Webhook.getGlobalUrl("getStats", {
options: { days: 30 },
redirect: "https://telebothost.com",
params: { ref: "home" }
})
Api.sendMessage({
text: `View global statistics: ${statsUrl}`
})
params for visible query strings (e.g., tracking or page context)options for internal, signed dataredirect if the webhook should lead back to an external pageuser-based URLs publicly| Method | Access Type | Use Case |
|---|---|---|
getGlobalUrl() | Public | Open APIs, landing pages |
getUrl() | Private (current user) | User dashboard, game data |
getUrlFor() | Private (specific user) | Account links, user actions |
The Webapp class is used to generate clean, global URLs for your bot’s
web integrations — such as dashboards, pages, or lightweight APIs.
Unlike Webhook, these URLs are not cryptographically signed,
making them ideal for open, public, or embed-style resources.
Use the Webapp class whenever you need a static or semi-dynamic link for:
getUrl(command, { options, params })
Generates a global webapp URL for the specified command.
You can include options for internal configuration
and params for visible query parameters.
let dashboardUrl = Webapp.getUrl("dashboard", {
options: { theme: "dark", userId: 123 },
params: { ref: "home", lang: "en" }
})
Api.sendMessage({
text: `Open the web dashboard: ${dashboardUrl}`
})
Webapp for public or semi-public resources onlyparams for readable URL parameters (e.g. ?ref=home&lang=en)options for app-level configurationWebhookres)
The res object allows webhook and Webapp commands to send structured HTTP responses.
It supports JSON, HTML, XML, text, redirects, and template rendering with EJS.
set(key, value)Sets HTTP headers on the response object.
res.set("Content-Type", "application/json")
.set("X-Custom-Header", "my-value")
status(code)Sets the HTTP response status code.
res.status(200)
res.status(404)
res.status(500)
send(body)Sends a response with any content type.
res.send("Hello World")
res.send({ message: "Success", data: { id: 1 } })
res.status(201).send("Resource created")
json(obj)Sends a JSON response with application/json content type.
res.json({
status: "success",
user: user.name,
data: processedData
})
html(content)Sends an HTML response. Auto-renders EJS templates if tags detected.
res.html("<h1>Welcome</h1><p>Hello World</p>")
res.html(`
<h1>Welcome <%= user.first_name %></h1>
<p>Your ID: <%= user.id %></p>
<% if (user.premium) { %>
<div class='premium'>Premium User</div>
<% } %>
`)
xml(content)Sends an XML response with application/xml content type.
res.xml('<?xml version="1.0"?><response><status>success</status></response>')
text(content)Sends a plain text response. Auto-renders EJS templates if tags detected.
res.text("This is plain text")
const textTemplate = 'Hello <%= name %>, welcome!'
res.text(textTemplate)
redirect(url)Redirects the request to a different URL.
res.redirect("https://example.com/success")
res.redirect("/another-command")
render(commandPath, options)Renders another command's code as response with automatic content type detection.
res.render("user-profile")
res.render("api-data.json", {
data: { user: { name: "John", age: 30 } }
})
res.render("dashboard.html", {
data: {
user: user,
stats: userStats,
params: params
}
})
res.render() automatically detects content type from file extension:
res.render("page.html") // Content-Type: text/html
res.render("data.json") // Content-Type: application/json
res.render("script.js") // Content-Type: application/javascript
res.render("style.css") // Content-Type: text/css
res.render("api.xml") // Content-Type: application/xml
res.render("plain-text") // Content-Type: text/plain
All template rendering methods have access to multiple data sources:
// Webhook URL: /webhook/showProfile?section=settings&view=compact
res.render("profile-template.html", {
data: {
user: user, // Current user object
profile: userProfile, // Additional profile data
preferences: userPrefs // User preferences
}
})
// In profile-template.html, you can access:
// - user, profile, preferences from data object
// - params (from URL query string: {section: "settings", view: "compact"})
// - All TBL variables (msg, Api, State, etc.)
let userData = {
id: user.id,
name: user.first_name,
premium: user.premium || false,
join_date: user.join_date
}
res.status(200)
.set("Access-Control-Allow-Origin", "*")
.json({
status: "success",
data: userData,
timestamp: Date.now()
})
.end()
// Command: dashboard-html (contains HTML template)
<!DOCTYPE html>
<html>
<head>
<title>Dashboard - <%= user.first_name %></title>
<style>
body { font-family: Arial; margin: 40px; }
.premium { color: gold; }
.section { margin: 20px 0; }
</style>
</head>
<body>
<h1>Welcome <%= user.first_name %> <%= user.last_name %></h1>
<% if (params.view === "compact") { %>
<div class="compact-view">
<p>Quick Overview</p>
</div>
<% } else { %>
<div class="full-view">
<div class="section">
<h3>Profile</h3>
<p>Email: <%= user.email %></p>
<p>Member since: <%= new Date(user.join_date).toLocaleDateString() %></p>
</div>
</div>
<% } %>
<% if (data.stats) { %>
<div class="section">
<h3>Statistics</h3>
<p>Total orders: <%= data.stats.totalOrders %></p>
<p>Account balance: $<%= data.stats.balance %></p>
</div>
<% } %>
</body>
</html>
// Command: showDashboard (renders the template)
let userStats = {
totalOrders: 15,
balance: 245.50
}
res.render("dashboard-html", {
data: {
stats: userStats
}
})
// URL: /webhook/showDashboard?view=compact
// Will render the compact view based on params.view
// Command: user-api.json (contains JSON template)
{
"status": "success",
"user": {
"id": <%= user.id %>,
"username": "<%= user.first_name %> <%= user.last_name %>",
"premium": <%= user.premium %>,
"join_date": "<%= user.join_date %>"
},
"request_params": {
"format": "<%= params.format %>",
"include_stats": <%= params.include_stats === "true" %>
},
"<%= params.include_stats === "true" ? "statistics" : "" %>": <% if (params.include_stats === "true") { %>{
"total_orders": <%= data.stats.orders %>,
"success_rate": <%= data.stats.successRate %>
}<% } else { %>null<% } %>
}
// Command: getUserData (renders the JSON template)
let userStatistics = {
orders: 42,
successRate: 95.5
}
res.render("user-api.json", {
data: {
stats: userStatistics
}
})
// URL: /webhook/getUserData?format=detailed&include_stats=true
// Outputs dynamic JSON based on parameters
// Command: start - send webhook URL to user
let dashboardUrl = Webhook.getUrl("showDashboard")
Api.sendMessage({
text: `Click here to access your dashboard: ${dashboardUrl}`,
parse_mode: "HTML"
})
// Command: showDashboard - render personalized view
if (!user) {
return res.status(401).json({ error: "User not found" })
}
res.renderEJS(`
<h1>Dashboard for <%= user.first_name %></h1>
<div>
<a href="<%= Webhook.getUrl('profile') %>">Profile</a> |
<a href="<%= Webhook.getUrl('settings') %>">Settings</a>
</div>
<% if (params.ref === "welcome") { %>
<div class="welcome-message">
Welcome to your new dashboard!
</div>
<% } %>
`)
// Command: error-template.html
<!DOCTYPE html>
<html>
<head>
<title>Error <%= data.error.code %></title>
</head>
<body>
<h1>Error <%= data.error.code %></h1>
<p><%= data.error.message %></p>
<% if (data.error.details) { %>
<div class="details">
<strong>Details:</strong>
<p><%= data.error.details %></p>
</div>
<% } %>
<a href="<%= Webhook.getUrl('home') %>">Return to Home</a>
</body>
</html>
// Command: protectedAction
if (!user || !user.hasAccess) {
return res.status(403).render("error-template.html", {
data: {
error: {
code: 403,
message: "Access Denied",
details: "You don't have permission to access this resource"
}
}
})
}
// Continue with normal processing...
The msg class lets you interact with Telegram messages.
You can send, reply, edit, delete, forward, copy, react, and perform chat actions.
All methods return promises, but using await is optional — only required if you need the response object.
msg.reply(), msg.send()msg.replyPhoto(), msg.replyVideo(), msg.replyDocument()msg.editText(), msg.delete(), msg.react(), msg.pin(), msg.unpin()msg.forward(), msg.copy()msg.replySticker(), msg.replyDice()msg.sendChatAction()
// Reply to the current message
msg.reply("Hello!") // Fire-and-forget
let result = await msg.reply("Hello!"); // Use await if you need the API response
// Send a new message
msg.send("This is a new message")
await msg.send("This is a new message", { parse_mode: "Markdown" }) // await optional
// Reply with a photo
msg.replyPhoto("https://example.com/cat.jpg", { caption: "Cute cat 🐱" })
await msg.replyPhoto("https://example.com/cat.jpg", { caption: "Cute cat 🐱" }) // await optional
// Reply with a video
msg.replyVideo("https://example.com/video.mp4")
await msg.replyVideo("https://example.com/video.mp4", { caption: "Watch this!" })
// Reply with a document
msg.replyDocument("file.pdf")
await msg.replyDocument("file.pdf")
// Edit message text
msg.editText("Updated text")
// Delete message
msg.delete(msg.message_id)
await msg.delete(msg.message_id)
// Add reactions
msg.react("👍")
msg.react("🔥", true) // Big emoji
// Pin & unpin messages only for group or super group with proper admin Rights
msg.pin()
msg.unpin(msg.message_id)
// Forward message
msg.forward(123456789)
await msg.forward(123456789)
// Copy message
msg.copy(123456789, { caption: "Copied message" })
await msg.copy(123456789, { caption: "Copied message" })
// Reply with a sticker
msg.replySticker("CAACAgUAAxkBAAECX-9g1...")
await msg.replySticker("CAACAgUAAxkBAAECX-9g1...")
// Reply with a dice
msg.replyDice("🎲")
await msg.replyDice("🎲")
// Show typing indicator
msg.sendChatAction("typing")
await msg.sendChatAction("typing") // await optional
// Other actions: "upload_photo", "record_video", "record_audio", "upload_document"
The msg object contains the full Telegram message data:
msg.text - Message textmsg.chat - Chat info (id, type, title, etc.)msg.from - Sender infomsg.message_id - Unique message IDmsg.date - TimestampAll methods also work in lowercase (e.g., msg.replyphoto).
Markdown parsing is enabled by default for text methods.
The modules object gives you access to popular Node.js libraries directly in TBL.
Use modules.moduleName.method() to perform common tasks like encryption, validation, date handling, CSV/YAML parsing, random data generation, and more.
JWT is used for creating and verifying JSON Web Tokens. Useful for authentication, session management, or secure data transfer.
Docs: jsonwebtoken
// Create a token
const token = modules.JWT.sign({ userId: 123 }, "secret");
// Verify a token
const decoded = modules.JWT.verify(token, "secret");
// Demo response:
// token → "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
// decoded → { userId: 123, iat: 1690000000 }
bcrypt hashes passwords and verifies them. Essential for secure password storage.
Docs: bcrypt
// Hash a password
const hash = await modules.bcrypt.hash("password123", 10);
// Verify password
const match = await modules.bcrypt.compare("password123", hash);
// Demo response:
// hash → "$2b$10$e0N...."
// match → true
crypto provides cryptographic functions, including hashing, encryption, and decryption.
Docs: Node.js crypto
// Create SHA256 hash
const hash = modules.crypto.createHash("sha256").update("data").digest("hex");
// Demo response:
// hash → "3a6eb...9f1"
Parses CSV strings into JSON objects. Useful for reading CSV files in bots or scripts.
Docs: csv-parse
// Parse CSV string
const result = modules.ParseCSV.parse("name,age\nAlice,25\nBob,30");
// Demo response:
// result → [{ name: "Alice", age: "25" }, { name: "Bob", age: "30" }]
Parses YAML strings into JSON objects. Useful for reading YAML configuration files.
Docs: js-yaml
// Parse YAML string
const result = modules.ParseYML.parse("name: Alice\nage: 25");
// Demo response:
// result → { name: "Alice", age: 25 }
Generates unique identifiers (UUID v4 or v6). Useful for unique keys, transaction IDs, or session identifiers.
Docs: uuid
// Generate v4 UUID
const id = modules.UUID.uuidv4();
// Demo response:
// id → "550e8400-e29b-41d4-a716-446655440000"
A powerful library for date and time manipulation. Format, parse, and calculate dates easily.
Docs: momentjs
// Format current date
const dateStr = modules.moment().format("YYYY-MM-DD");
// Demo response:
// dateStr → "2025-09-19"
A utility library for array, object, and function operations. Very handy for filtering, mapping, and transforming data.
Docs: lodash
// Filter array
const result = modules.lodash.filter([1,2,3,4], n => n > 2);
// Demo response:
// result → [3,4]
Generates random alphanumeric strings, useful for temporary passwords, tokens, or unique identifiers.
Docs: randomstring
// Generate 10-character random string
const str = modules.randomstring.generate(10);
// Demo response:
// str → "a1b2c3d4e5"
Validates strings like emails, URLs, and other formats.
Docs: validator
// Validate email
const valid = modules.validator.isEmail("test@example.com");
// Demo response:
// valid → true
Generates random data, such as names, addresses, and phone numbers.
Docs: chancejs
// Generate random name
const name = modules.chance.name();
// Demo response:
// name → "Alice Johnson"
Mathematical functions like square root, powers, trigonometry, etc.
Docs: mathjs
// Square root
const val = modules.math.sqrt(25);
// Demo response:
// val → 5
Parses and formats query strings.
Docs: qs
// Parse query string
const obj = modules.qs.parse("a=1&b=2");
// Demo response:
// obj → { a: "1", b: "2" }
Parse and manipulate HTML in Node.js (like jQuery). Useful for scraping and DOM manipulation.
Docs: cheerio
// Load HTML
const $ = modules.cheerio.load("<p>Hello</p>");
const text = $("p").text();
// Demo response:
// text → "Hello"
Lightweight alternative to Moment.js for date and time operations.
Docs: dayjs
// Format current date
const today = modules.dayjs().format("YYYY-MM-DD");
// Demo response:
// today → "2025-09-19"
//We have our own Basic library for time parsing too
Schema validation library for structured data. Useful for input validation.
Docs: zod
// Validate string
const result = modules.zod.string().parse("Hello");
// Demo response:
// result → "Hello"
Generates short unique IDs for objects, users, or temporary references. Useful when you need compact unique identifiers.
Docs: shortid
// Generate short ID
const id = modules.shortid.generate();
// Demo response:
// id → "ppBqWA9"
Deeply merges multiple objects. Useful for combining configs or nested data structures.
Docs: deepmerge
// Merge two objects
const merged = modules.deepmerge({ a: 1, b: { x: 1 } }, { b: { y: 2 }, c: 3 });
// Demo response:
// merged → { a: 1, b: { x: 1, y: 2 }, c: 3 }
Formats durations (milliseconds) into human-readable strings, like "2 hours" or "5 minutes".
Docs: humanize-duration
// Convert milliseconds to human-readable
const duration = modules.humanizeDuration(3600000);
// Demo response:
// duration → "1 hour"
Parses user-agent strings to extract browser, OS, and device information. Useful for analytics, logs, or customizing content.
Docs: ua-parser-js
// Parse user-agent
const ua = modules.uaParser.parse("Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
// Demo response:
// ua → { browser: { name: "Firefox", version: "xx" }, os: { name: "Windows", version: "10" }, device: { model: "", type: "", vendor: "" } }
You no longer need to use modules.crypto.xxx; you can directly access methods with crypto.xxx.
The crypto library is now included by default since it’s one of the most commonly used modules.
Similarly, the form-data library is also included by default as FormData, allowing you to use FormData.xxx directly.
The Libs class gives direct access to TBL’s built-in libraries.
Each library contains ready-to-use helpers for randomization, date/time operations, resource tracking, referral systems, Telegram utilities, and membership checking.
Use the syntax Libs.<library>.<method>().
Most methods return promises—await is optional unless you need the returned value.
// Create or get a user resource (e.g., balance)
let coins = Libs.ResourcesLib.userRes("coins")
coins.add(50) // add value
let current = coins.value() // get current value
// Global resource example
let globalCounter = Libs.ResourcesLib.anotherRes("visits")
globalCounter.add(1)
Persistent storage for user or global properties. Full ResourcesLib Documentation
// Current date/time in custom mask
let now = Libs.dateTimeFormat.getCurrentDate("yyyy-mm-dd HH:MM:ss")
// Add days to a date
let future = Libs.dateTimeFormat.addDays(new Date(), 7)
// Time difference between two dates
let diff = Libs.dateTimeFormat.getTimeDifference("2025-01-01","2025-02-01")
Full set of date formatting and calculation utilities. Full dateTimeFormat Documentation
// Check if a user is a member of specific channels
let joined = await Libs.mcl.check(user.id, ["@Chan1", "@Chan2"])
/* returns
{
all_joined: true,
valid: [ '@Channel1', '@Channel2' ],
left: [],
invalid: [],
details: [
{
channel: '@Channel1',
member: { /* full getChatMember response */ }
}
]
}
*/
Validate user subscriptions across one or more Telegram channels or groups before allowing bot actions. Full MCL Documentation
// Random integer between 1 and 10
let num = Libs.random.randomInt(1, 10)
// Random string of 8 letters
let str = Libs.random.randomString(8, { charset: "alpha" })
// Random date within range
let date = Libs.random.randomDate(new Date(2023,0,1), new Date(2025,0,1))
// Random color
let color = Libs.random.randomColor("rgb")
Comprehensive random generation utilities. Full random Documentation
// Create a referral link
let refLink = Libs.refLib.getRefLink(bot.name)
// Count referrals for a user
let count = Libs.refLib.getRefCount(user.id)
Tools for building and tracking referral systems. Full refLib Documentation
// Get a user’s full name
let fullName = Libs.tgutil.getFullName(user)
// Create a clickable HTML link to a user profile
let link = Libs.tgutil.getLinkFor(user, "html")
// Escape text for Markdown
let safeText = Libs.tgutil.escapeText("*Hello*", "markdown")
// Create an inline button
let btn = Libs.tgutil.createInlineButton("Press Me", "/callback_data")
Telegram-specific helpers for mentions, chat links, message links, and safe text formatting. Full tgutil Documentation
await only if the lib is asynchronous like MCL lib
The TBL class provides methods to manage bots in TeleBotHost.
You can clone bots, transfer bot using this class
TBL.clone creates a copy of an existing bot, optionally including all properties and starting it immediately.
You can also pass custom properties to the cloned bot.
const res = TBL.clone({
bot_id: bot.id, // Required: ID of the bot to clone
start_now: true, // Optional: start cloned bot immediately
bot_token: '12345:abc', // Required if start_now=true
all_prop: true, // Optional: copy all bot properties
bot_props: { // Optional: custom properties
theme: 'dark',
welcome: 'Welcome to my new bot!'
}
});
// Inspect the cloned bot
Bot.inspect(res);
TBL.transfer allows you to transfer the bot to another TeleBotHost user.
const result = TBL.transfer({
bot_id: bot.id, // Bot ID to transfer
to_mail: 'newuser@telebothost.com' // Target owner's email
});
TBL.clone and TBL.transfer are synchronous and return immediately after the operation finishes.Bot.inspect(res) to verify bot details after cloning or transferring.start_now: true, ensure a valid bot_token is provided.bot_props are automatically type-detected (string, number, boolean, etc.).This page describes the current known issues with how errors work in TBL. These are temporary behaviors that will be fixed or improved in future updates.
Currently, errors inside Bot.run() or Bot.runCommand() only throw when the function is awaited.
If you call them without await, the error will not be thrown — it will silently fail.
// Only throws when awaited
await Bot.run("/invalid_command")
// This will not throw, error ignored
Bot.run("/invalid_command")
This is a known issue and will be fixed so that Bot.run() properly reports errors even when not awaited.
At the moment, Telegram API errors (such as invalid parameters, missing chat IDs, or access errors) are silent — they do not throw or stop script execution. These errors only appear in the website’s Error Tab logs.
// Example: text can't be empty
Bot.sendMessage("")
// This error will only appear in Error Tab logs
Future updates will make these errors more visible and optionally throwable for better debugging.
HTTP request errors (network issues, bad URLs, or invalid responses) currently behave silently.
They are not logged in the dashboard and do not throw exceptions.
The only indication is through the res.error field returned in the response.
let res = await HTTP.get("https://invalid.url")
if (res.error) {
Bot.sendMessage("HTTP error: " + res.error)
}
In the future, these errors will be logged and optionally displayed in the Error Tab for better tracking.
await.These changes are planned for the next update to make error handling more predictable and developer-friendly.
The Free Plan in TBL provides a secure sandbox for running bots with limited resources. It’s designed for small projects, testing, and basic automation.
Promise.all()