TBL Language Reference

Full reference guide for TBL (Tele Bot Lang)

Introduction

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.

Key Features

TBL scripts are command-based, meaning they respond to specific triggers instead of listening for events.

Getting Started

This section explains the basic steps to create and test your first Telegram bot using TBL.

Step 1: Create a Telegram Bot

  1. Open Telegram and search for @BotFather.
  2. Send /newbot to create a new bot.
  3. Choose a name and a username (must end with bot).
  4. Copy the generated bot token.
const botToken = "123456789:ABCdefGhIJKlmNoPQRsTUVwxyZ";

Step 2: Register on TBL Platform

  1. Log into the TBL platform.
  2. Click "Create New Bot".
  3. Enter the bot name and paste the token from BotFather.
  4. Click "Create" to initialize your bot.

Step 3: Add Basic Commands

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")

What's New in TBL

The latest TBL update introduces major new features for developers, giving more control, flexibility, and integration possibilities. Here’s a breakdown of everything new:

1. Webhook Support

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.

2. New Bot.read() Method

A 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.

3. Buffer Support

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.

4. Improved 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.

5. Dynamic Command Handlers

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.

Special Commands like /inline_query and /channel_update are still supported and prioritized.

Summary

Command Structure

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.

Anatomy of a Command

A command can include these parts:

Example Command

Bot.sendMessage("Hello " + user.first_name + "!")

In this example:

Answer

Answers 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...")

Need Reply

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

Aliases let one command have multiple triggers.

/*Command: /hello
aliases: hi, hey, hola*/
Bot.sendMessage("Hello there!")

Keyboards

Commands can show custom keyboards:

/*Command: /menu
answer: Choose an option:
keyboard: Yes,No\nMaybe*/
Bot.sendMessage("Waiting for your choice...")

Special Commands

TBL provides special system-level commands:

Dynamic Update Handlers

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:

If 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.

/inline_query

Handles inline mode queries (when users type @yourbot query in Telegram).

Command: /inline_query
Bot.sendMessage("You searched: " + request.query)

/channel_update

Handles channel posts automatically.

Command: /channel_update
Bot.sendMessage("New channel post received!")

Best Practices

Always define a ! command to capture and handle runtime errors.

Global Predefined Values

TBL 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.

update

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"
      }
    ]
  }
}

request

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..

message

Contains only the text of a message (if applicable).

"Hello bot"

user

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
}

chat

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
}

bot

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."
}
  

params

Extra text after a command. Example: "/start hello" → params = "hello".

"hello"

options

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": {...}
}
  

content

Contains the response body from an HTTP request.

inspect()

Helper function to print any object for debugging.

like if you did inspect(data) it will return bot Details

msg

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.

error

It's a object that gives information about error got by ! command

Global Classes

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.

Api

The Api class lets you call any Telegram method. You can use it directly, with callbacks, async/await, or with chained message methods.

Api methods are case insensitive. You can use both sendMessage or sendmessage.

1. Simple Usage

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" })
  

2. Using 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 })
}
  

3. Using Async / Await

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
  

4. Chained Methods on Api.xxx 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

  

Supported Chained Methods

Bot Class

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.

Available Methods

The following methods are available in the Bot class:

Bot methods are case sensitive, so only strict name allowed like sendMessage and sendmessage are treated as separate methods.

1. Command Execution

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
Currently, Bot.run() and Bot.runCommand() errors only throw when awaited.
Example: await Bot.run("/cmd") will throw, but Bot.run("/cmd") will silently fail.
This issue will be fixed in future versions.

2. Reading Command Code

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)

3. Sending Messages

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 

4. Properties

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"]

Supported Property Data Types

The following data types are supported when storing bot properties:

The type parameter is optional in Bot.set(). If not provided, the type is automatically detected.

5. Property Aliases

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()

HTTP Class

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.

1. GET Requests

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)

2. POST Requests

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)

3. Success / Error Commands with 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)

4. Advanced Options


// 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"
})

Usage Notes

User Class

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.

1. Basic Operations

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

2. Deleting Properties

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

3. Bulk Operations

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)
// → {}

4. Checking & Counting

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"] }

Notes

Webhook

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.

Webhook URLs are signed and verified automatically. They can be global (open for everyone) or user-based (private to a specific user).

Webhook Types

Global Webhooks

Global webhooks are public endpoints anyone can access. Ideal for open integrations, landing pages, or APIs that don’t require authentication.

User-Based Webhooks

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 Methods

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}`
})

Best Practices

MethodAccess TypeUse Case
getGlobalUrl()PublicOpen APIs, landing pages
getUrl()Private (current user)User dashboard, game data
getUrlFor()Private (specific user)Account links, user actions

Webapp

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.

Webapp URLs are public and do not contain user authentication data. They are best used for pages that do not need secure user verification.

When to Use

Use the Webapp class whenever you need a static or semi-dynamic link for:

Webapp Methods

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}`
})

✨ Best Practices

Response Object (res)

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.

Response Methods

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() In-Depth

Automatic Content Type Detection

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

Data Passing and Template Context

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.)

Practical Examples

Example 1: JSON API Endpoint

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()

Example 2: User Dashboard with res.render()

// 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

Example 3: Dynamic JSON API with res.render()

// 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

Example 4: Complete Webhook Flow

// 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>
  <% } %>
`)

Example 5: Error Handling with res.render()

// 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...
Security Note: All webhook URLs are digitally signed and protected against tampering. Always validate actions on your server, and never rely solely on client-side data.

msg Class

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.

Available Methods

1. Core Messaging


// 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

2. Media Messages


// 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")

3. Message Management


// 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)

4. Forwarding & Copying


// Forward message
msg.forward(123456789)
await msg.forward(123456789)

// Copy message
msg.copy(123456789, { caption: "Copied message" })
await msg.copy(123456789, { caption: "Copied message" })

5. Special Messages


// Reply with a sticker
msg.replySticker("CAACAgUAAxkBAAECX-9g1...")
await msg.replySticker("CAACAgUAAxkBAAECX-9g1...")

// Reply with a dice
msg.replyDice("🎲")
await msg.replyDice("🎲")

6. Chat Actions


// Show typing indicator
msg.sendChatAction("typing")
await msg.sendChatAction("typing") // await optional

// Other actions: "upload_photo", "record_video", "record_audio", "upload_document"

7. Message Object Access

The msg object contains the full Telegram message data:

All methods also work in lowercase (e.g., msg.replyphoto). Markdown parsing is enabled by default for text methods.

Modules Class

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.

1. JWT

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 }

2. bcrypt

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

3. crypto

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"

4. ParseCSV

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" }]

5. ParseYML

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 }

6. UUID

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"

7. moment

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"

8. lodash

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]

9. randomstring

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"

10. validator

Validates strings like emails, URLs, and other formats.

Docs: validator


// Validate email
const valid = modules.validator.isEmail("test@example.com");

// Demo response:
// valid → true

11. chance

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"

12. math

Mathematical functions like square root, powers, trigonometry, etc.

Docs: mathjs


// Square root
const val = modules.math.sqrt(25);

// Demo response:
// val → 5

13. qs

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" }

14. cheerio

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"

15. dayjs

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

16. zod

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"

17. shortid

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"

18. deepmerge

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 }

19. humanizeDuration

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"

20. uaParser

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: "" } }

Crypto & FormData Module Update

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.

Libs Class

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.

Available Libraries

1. ResourcesLib


// 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

2. dateTimeFormat


// 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

3. MCL – Membership Checker


// 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

4. random


// 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

5. refLib


// 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

6. tgutil


// 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

Usage Tips

TBL

The TBL class provides methods to manage bots in TeleBotHost. You can clone bots, transfer bot using this class

1. Clone Bot

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);
Important: Cloning may take upto 4–5 seconds to complete.

2. Transfer Bot

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
});
Important: Transferring a bot may take 4–5 seconds. The method is synchronous and blocks execution while the server completes the transfer.

Notes & Best Practices

Current Error Behaviors

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.

1. Bot.run() and Bot.runCommand() Errors

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.

2. Telegram API Errors Are Silent

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.

3. HTTP Errors Are Silent and Unlogged

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.

Planned Fixes

These changes are planned for the next update to make error handling more predictable and developer-friendly.

TBL Free Plan Limits

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.


Execution

File System

Persistent Storage (Properties)

Support