# Welcome

## Bots.Business Help

Download from [Play Market](https://play.google.com/store/apps/details?id=bb_app.com.bots.business)

## Create your own bot for Telegram from new app Bots.Business.

### How to create bot

1. Create bot with @BotFather
2. Now create bot in app: add secret token
3. Create commands&#x20;

See [more](https://help.bots.business/getting-started)

### Install bots from the Store

{% hint style="info" %}
In the store are available various bots. Do you need referal tracking? Or chat with yours users via bot? This and the other is in the Bots Store!
{% endhint %}

In the store are available various bots. Do you need referal tracking? Or chat with yours users via bot? This and the other is in the Bots Store!

### Commands

Command can have: `name`, `help`, `aliases` (second names), `answer`, `keyboard`, `scnarios` (for simple logic) and other options.

####

#### CSV import with Google Table

Do you have much commands? Use Google Table and make import! Generate commands with formulas and do more with Google Table.

**Template table** <http://bit.ly/bb_table_template>

**Demo bot @DemoFromTableBot from this table** <http://bit.ly/DemoFromTableBot>

#### How to import CSV file

1. Create Google Table with commands for bot (You can use template)
2. Do publich this Table in CSV format via File menu
3. Paste CSV url in application and do upload command

Now you can talk with yours new Telegram Bot

See [more](https://help.bots.business/create-bot-from-google-table)

## BJS for command

Use Bot Java Script for logic in command.

See [more](https://help.bots.business/scenarios-and-bjs)

## FAQ

<https://help.bots.business/howto>

## API

[appapi.bots.business/docs](https://appapi.bots.business/docs)


# Getting started

Get bot Token with @BotFather

## &#x20;How do I create a bot?

There's a… bot for that. Just talk to [@BotFather](https://telegram.me/BotFather) and follow a few simple steps. You need your authorization token.

The **token** is a string along the lines of *`110201543:AAHdqTcvCH1vGWJxfSeofSAs0K5PALDsaw`* that is required to authorize the bot

Now go to app and fill this token in bot creation form.

![](/files/-LWKB7lbyGA5TrG2gkGm)

## Help videos by community

See [video](https://youtu.be/MZixi8oIdaA) - how to get bot token

[How to make](https://www.youtube.com/watch?v=2-bR54obN4w) simple bot


# Create bot from Google Table

## Do you have any Google Table? You can create Bot from it!&#x20;

You need the list with commands. See demo table [here](https://docs.google.com/spreadsheets/d/1hLEeCGqT5zTtT7hFs0HP20v5BrRj1y70Qhz4bOItO-c/edit?usp=sharing).

You can make copy from this table (File->Copy in Google Table) or copy list to your own table. (Ctrl+C and Ctrl + V)

![](/files/-LWKCw11BjhBmIXJBq9c)

{% hint style="info" %}
See [demo bot](https://telegram.me/DemoFromTableBot) from this Demo Table
{% endhint %}

### How to do import from table?

Publish list (prefer to use computer) with commands in the web as CSV file:&#x20;

![](/files/-LWKGgwF0t1HClrDSX6R)

###

### What it is: command, answer, aliases...?

See [here](https://help.bots.business/commands)

### How do I import a commands?

* Open a copied table file in Sheets in browser. (Prefer to use computer)
* At the top, click File and then Publish to the web.
* Choose "List1" and "File CSV"
* Press buton "Publish"
* Copy your table link - **CSV url**

Paste **Token** and **CSV url** in app.

* Create new bot in app
* Paste **Token** and **CSV url (in Advanced fields)**
* Create and make upload!


# MCP

## How to connect Bots.Business MCP to your AI client

Bots.Business supports MCP — Model Context Protocol.

MCP allows AI clients to connect to your Bots.Business account and use available tools through secure OAuth authorization.

For most users, the setup is simple: add the MCP server URL to your AI client and connect your Bots.Business account.

### MCP Server URL

Use this URL:

```
https://appapi.tgbot.ai/mcp
```

Add it as an MCP server URL in your AI client.

After that, the AI client should open the Bots.Business login page. Log in to your Bots.Business account and approve the connection.

Your Bots.Business password is not shared with the AI client. The connection uses OAuth authorization.

***

### Basic setup

1. Open MCP / Connectors settings in your AI client.
2. Add MCP server URL:

```
https://appapi.tgbot.ai/mcp
```

3. Click **Connect**.
4. You will be redirected to Bots.Business login.
5. Log in to your Bots.Business account.
6. After successful login, the AI client will receive access to Bots.Business MCP tools.

***

### ChatGPT Connector setup

If Bots.Business MCP is used as a ChatGPT Connector, the end user usually does not need to configure OAuth manually.

The connector administrator should use this MCP URL:

```
https://appapi.tgbot.ai/mcp
```

OAuth must be enabled.

The ChatGPT OAuth redirect URL is supported:

```
https://chatgpt.com/connector/oauth/*
```

After the connector is configured, the user only needs to click **Connect**, log in to Bots.Business, and start using the available tools.

***

### For generic MCP clients

Bots.Business MCP server URL:

```
https://appapi.tgbot.ai/mcp
```

OAuth discovery endpoints:

```
https://appapi.tgbot.ai/.well-known/oauth-protected-resource
https://appapi.tgbot.ai/.well-known/oauth-authorization-server
```

OAuth endpoints:

```
Authorization URL: https://appapi.tgbot.ai/oauth/authorize
Token URL: https://appapi.tgbot.ai/oauth/token
```

OAuth parameters:

```
Scopes: read write
PKCE: S256
resource: https://appapi.tgbot.ai
Client ID: bots-business-mcp
```

Important: `resource` must be the external base URL without `/mcp`.

Correct:

```
resource=https://appapi.tgbot.ai
```

Incorrect:

```
resource=https://appapi.tgbot.ai/mcp
```

***

### Transport

Bots.Business MCP v1 supports stateless Streamable HTTP JSON-RPC.

Use:

```
POST /mcp
```

Example request:

```
POST https://appapi.tgbot.ai/mcp
Authorization: Bearer <access_token>
Content-Type: application/json
```

`GET /mcp` is not supported and will return:

```
405 Method Not Allowed
```

This is expected behavior. MCP clients should use `POST /mcp`.

SSE is not used in v1.

***

### Manual checks

Check OAuth discovery:

```
curl https://appapi.tgbot.ai/.well-known/oauth-protected-resource
```

Check MCP initialize:

```
curl -X POST https://appapi.tgbot.ai/mcp \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18"}}'
```

To call tools, use an OAuth access token:

```
curl -X POST https://appapi.tgbot.ai/mcp \
  -H 'Authorization: Bearer <access_token>' \
  -H 'Content-Type: application/json' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
```

***

### Troubleshooting

#### GET /mcp returns 405

This is normal.

Bots.Business MCP works through `POST /mcp`.

Use:

```
POST https://appapi.tgbot.ai/mcp
```

Do not use:

```
GET https://appapi.tgbot.ai/mcp
```

***

#### wrong\_resource error

If the token is rejected with `wrong_resource`, the OAuth `resource` does not match the external base URL.

The correct resource is:

```
https://appapi.tgbot.ai
```

It must not include `/mcp`.

If the application is running behind a proxy, make sure the backend sees the correct external protocol and host.

For example, if the backend thinks its base URL is:

```
http://localhost
```

or another internal host, the MCP token may be rejected as `wrong_resource`.

Check your proxy headers and external `base_url` configuration.

***

### Summary

For most users, only one URL is needed:

```
https://appapi.tgbot.ai/mcp
```

Add it to your AI client, click **Connect**, log in to Bots.Business, and the MCP tools will become available


# App

This is a help section for the app. Please select a sub-article.


# Reset or Update Your Password

## Forgot Password

If you forgot your password and unable to login the app, follow this steps.

#### Steps:

1. Click **"Forgot Password"** on the login page.\
   [![Forgot Password Screenshot](https://camo.githubusercontent.com/d07d105f06ccc338f71728790a605c205dc4db419e0428bea2dd05edcf5162e9/68747470733a2f2f692e6962622e636f2f4e67436b47596b672f32303235303133302d3133333535372e706e67)](https://camo.githubusercontent.com/d07d105f06ccc338f71728790a605c205dc4db419e0428bea2dd05edcf5162e9/68747470733a2f2f692e6962622e636f2f4e67436b47596b672f32303235303133302d3133333535372e706e67)
2. Enter your **registered email** and click **Reset my password** button.
3. Check your inbox for a **new password**, we will send a brand new password to your email. check spam folder if you unable to find the email with password.
4. Log in using the new password.

{% hint style="success" %}
**Success!**&#x20;

You can now log in and optionally update your password via the **Bots Business App**.
{% endhint %}

### Update password

If you think your password isn't secured or someone gain access to it, you can easily update your password and make it secure.

#### Steps:

1. Open the App and click on thee line (top-left corner), then click on your profile.
2. Scroll a little bit to see the update password section.\
   [![BB App Profile Screenshot](https://camo.githubusercontent.com/85aa9c2fe058417742cc94fc27512118b9ac859d1edf12e3f2511ee8d3110c51/68747470733a2f2f692e6962622e636f2f52346b63425246362f53637265656e73686f742d323032352d30312d33302d31332d35372d32362d3934372d62622d6170702d636f6d2d626f74732d627573696e6573732d656469742e6a7067)](https://camo.githubusercontent.com/85aa9c2fe058417742cc94fc27512118b9ac859d1edf12e3f2511ee8d3110c51/68747470733a2f2f692e6962622e636f2f52346b63425246362f53637265656e73686f742d323032352d30312d33302d31332d35372d32362d3934372d62622d6170702d636f6d2d626f74732d627573696e6573732d656469742e6a7067)
3. Enter your **current password**.
4. Set and confirm a **new password**.
5. Tap **Update Password**.

{% hint style="success" %}
**Success!** Your password is updated instantly.{
{% endhint %}

### Recover password

If you lost access to your email account and forgot your password, we have a great solution for this,

#### Steps:

1. Visit [**@BotsBusinessAdminBot**](https://t.me/BotsBusinessAdminBot) bot.
2. Select **"Password Recovery"** from the menu.\
   [![Password Recovery Screenshot](https://camo.githubusercontent.com/6daa2f7bf0aa395c5390a284fd7dd896d54bd2d6e137ec8982ecd349b87cc384/68747470733a2f2f692e6962622e636f2f7339535a577471482f32303235303133302d3134303633352e6a7067)](https://camo.githubusercontent.com/6daa2f7bf0aa395c5390a284fd7dd896d54bd2d6e137ec8982ecd349b87cc384/68747470733a2f2f692e6962622e636f2f7339535a577471482f32303235303133302d3134303633352e6a7067)
3. Send a valid **bot token** from [**@BotFather**](https://t.me/BotFather).
4. After verification, you’ll get a **new password**.

{% hint style="info" %}
**Important Notes:**

* **Cloud accounts are NOT supported** for Telegram recovery.
* All active sessions will be **logged out**.
* Your **BB API Key will be reset** for security.
  {% endhint %}

### Troubleshooting

* Didn’t get the email? **Check spam** or request again.
* Password not working? **Try resetting again**.
* Still having trouble? [**Contact Support**](https://t.me/BotsBusinessAdmin).

### Password Security Tips

* **Never share your password** with anyone.
* Use a **password manager** for stronger security.

{% hint style="success" %}
Now you know how to reset or update your password easily—choose the method that works best for you!
{% endhint %}


# Commands

What it is "bot command"?

{% embed url="<https://youtu.be/2r5-Sb1Ce-4>" %}

Command - it is text from user. Bot can sent answer for command or do something. Usually command start with `"/"`, e.g. `/hello`. But it is not always required.

{% hint style="warning" %}
`/start` and `/START` - it is not same commands. Command is case sensitive
{% endhint %}

### How to execute command with any text from user? (Master command)

Just use `*` in command name.&#x20;

See [more](https://help.bots.business/scenarios-and-bjs/always-running-commands)

### Command's fields

Command can have:

| Field        | Description                                                                                                   | Example                                                                                                                     |
| ------------ | ------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `command`    | use for command call                                                                                          | <p><code>"/start"</code>, <code>"/run"</code>. For any text use <code>"\*"</code></p><p><strong>case sensitive</strong></p> |
| `help`       | command's description                                                                                         | `"Welcome to RentBot. See /help or /order now"`                                                                             |
| `answer`     | text answer                                                                                                   | `"Hello. You need /register before continue"`                                                                               |
| `aliases`    | use for alternative command call                                                                              | `"/welcome, /hello, ?, help"`                                                                                               |
| `keyboard`   | send keyboard to user on command call                                                                         | `"order, about"`                                                                                                            |
| `scenarios`  | `BJS` code for execution                                                                                      | `2+2`                                                                                                                       |
| `group`      | command allowed only for this user's group                                                                    | `guests`, `clients`                                                                                                         |
| `need_reply` | command wait for answer from user. Can be true, false or blank. If `true` BJS code execute after users'answer | `true`, `false`                                                                                                             |
| `auto_retry` | command can be runs with interval in secs                                                                     | `600` - repeated once at 10 minutes                                                                                         |

### How to create and edit commands?

You can edit command directly from application.

<figure><img src="/files/roBecMSuc9lvR4RSSLcS" alt=""><figcaption></figcaption></figure>

### Commands importing

Make all commands with [Google Table. ](https://help.bots.business/create-bot-from-google-table)

Also you can copy Template table from <http://bit.ly/bb_table_template> into your own table.&#x20;

This is an ideal option: everything is quite simple. Go to `Main menu > File > Make a copy`. You will need a separate sheet for the commands that will contain the commands. Then you can add commands in rows and do the CSV import from application.

###


# Answer

{% hint style="info" %}
Answer - it is simple text message from bot on command execition.
{% endhint %}

![Answer can be modified on command editing ](/files/-LWYQvWPsBniLhhf5YaR)

### How to format command's answer?

Use markdown text:

````
\n - new line (multi-line text also allowed)
*bold text*
_ italics _
[text](URL)
`inline fixed-width code`
```text
pre-formatted fixed-width code block
````

### How to insert a link to the answer?

```
[link text](url)
```

Example:

```
[Google](http://google.com)
```

### How to insert a picture to the answer?

```
[picture title](url)
```

Example:

```
[Dog](http://example.com/images/dog.jpg)
```

Also you can send picture file directly with BJS.

### How to insert a other command to the answer?

Just use such text `/command`

Example:

```
Hello! You can now /register or read /help
```

### How to insert a link to other command on the answer?

It can be with "/", e.g.: `/help`. Otherwise, unfortunately, no.


# Aliases

### What it is aliases?

Sometimes it is convenient to set aliases. For example, include aliases `/phone, /email` to command `/contacts`.\
Then `/contacts` - it is command name. Others - it's aliases.

![Aliases can be modified on command editing ](/files/-LWYRZyE09rGrDvuSDBq)

A much more useful case: set aliases for **keyboard** keys. Quite pleasant "contact" on the button, than "/contacts"

![](/files/-LWYS8_zwVPkyRuIxtKN)


# Keyboard

Fill the keyboard field for command. Keyboard has buttons in the rows. Each button is separated by a comma. Use `\n` for a new row.

![Keyboard in bot](/files/-LWYSKKzHSfETMxcP8Af)

Example:

```
register, about, \n contacts
```

**The text of the button will be placed in the chat after touching this button.** Use commands aliase on button. Quite pleasant "contact" on the button, than "/contacts"

Emoji also possible. Then the alias should also be with Emoji.

![ Keyboard can be modified on command editing ](/files/-LWYT9_sS44IylzeYYUX)

{% hint style="info" %}
The keyboard does not disappear after the user's answers. Bot can send a new keyboard on a new command.
{% endhint %}


# Groups

## What it is: "allowed only for group"?

Users can be members of the group.&#x20;

For example, there may be a group of "customers" and "guests." Then you can make sure that guests can not execute client commands.

![Group can be modified on command editing](/files/-LWYSVIMhBLBV1QcQBuP)

{% hint style="info" %}
You can use BJS code for adding user to group:`User.addToGroup(group_name)`&#x20;
{% endhint %}


# Wait for answer

## What it is "Wait for answer"?

It is need the `Wait for answer` flag if need a response from the user.

![Can be modified on command editing](/files/-LWYTNRAwL02vuuszlcY)

Example of execution of one command:

Bot:

> What is your name?

User:

> Jon

Bot:

> Hello, Jon

command:

```javascript
answer: What is your name?
need_reply: true
BJS: Bot.sendMessage( "Hello, " + message );
```

So BJS code execute only after user's answer

## How to cancel "Wait for"?

Example of canceled for command with "Wait for":

Bot:

> What is your name?

User (press "❌ Back" on keybord):

> ❌ Back

BJS:

```javascript
if(message=="❌ Back"){
   return  // exit from command on "Back"
}

Bot.sendMessage( "Hello, " + message );
```

or you can run /menu command on "Back"

```javascript
if(message=="❌ Back"){
   Bot.runCommand("/menu")
   return // exit from command on "Back"
}

Bot.sendMessage( "Hello, " + message );
```


# Auto Retry (AR)

Command can be run periodically. For example:

* bot send [message "Hello" ](https://help.bots.business/store/welcome-bot#good-morning-every-day)every 24 hours
* bot download web page every 1 hour and parse it. See our [PlayMarketNewsBot](https://telegram.me/PlayMarketNewsBot)

{% hint style="danger" %}
Auto Retry spent 1 iteration on each run. Thus, if you put AR for once a minute (60 secs), it will be 1440 iterations per day.
{% endhint %}

So it is need set auto retry time:

* for 10 minutes: 60\*10 = **600** secs
* for 1 hour: 60\*60 = **3600** secs
* for 24 hours: 60\*60\*24 = **86400** secs.
* for 1 year: 86400 \* 365 = **24966000** secs

#### Modify Auto Retry in app on command editing:

<figure><img src="/files/twCHUyIW02gtyhQJeQVd" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Auto retry works only with [BJS](https://help.bots.business/scenarios-and-bjs). There are now [Variables](https://help.bots.business/scenarios-and-bjs/variables): chat, user, request.
{% endhint %}

### Handled only on BJS!

Because Auto Retry initialized by automatic there are no current chat, user and request.&#x20;

So we can not use:

```javascript
Bot.sendMessage("Hello");  //not works with Auto Retry
```

Why? Bot do not know chat for sending message! No current chat.

So it is need define chat:

```javascript
Bot.sendMessage({text: "Hello", chat_id: YOUR_CHAT_ID});
```

#### How I can know chat id?

Create simple command (without Aoto Retry): `/chat` with BJS:

```javascript
Bot.sendMessage(chat.chatid);
```

And run it on that chat where you need Auto Retry later. This command return YOUR\_CHAT\_ID

Fill it in previous command with Auto Retry.

{% hint style="info" %}
You can use Bot.getProperty and Bot.setProperty. So you can save chat\_id in one command and then get it on Auto Retry command&#x20;
{% endhint %}

{% hint style="warning" %}
You can not use User.getProperty and User.setProperty.&#x20;

No user on Auto Retry!
{% endhint %}


# Coding: BJS

### What are these scenarios in the command?

Command can have some scenarios with BJS code.&#x20;

{% hint style="info" %}
BJS - it is "Bot Java Script" code.

It is Java Script!
{% endhint %}

Example. Calculating `2+2` and send result to the chat:

```javascript
Bot.sendMessage(2+2);
```

On command executing, its scenarios are executed sequentially and isolated.

{% hint style="success" %}
In BJS, you can use all the usual JS functions except setTimeout, setInterval
{% endhint %}


# Variables

In BJS we have useful global variables.

| **Variable**                                                         | **Description**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| -------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| <p>tgUpdate</p><p></p><p><em>Old name: request (deprecated)</em></p> | <p>it is collection with a lot of data. You can see it by: </p><p><code>Bot.inspect(tgUpdate)</code></p><p></p><p>All fields available <a href="https://core.telegram.org/bots/api#update">here</a>. All field will be in request.<br><br>With tgUpdate you can track all updates. <a href="/pages/-LsWOlRvn5_RXefEJC9L#all-updates">Read more</a></p>                                                                                                                                                                                                                           |
| message                                                              | current message from user - string                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               |
| user                                                                 | <p>user who sent a command or text. </p><p></p><p><strong>Fields:</strong> <br>id (BB id), </p><p>telegramid (telegram id),</p><p>first\_name,</p><p>last\_name,</p><p>username, </p><p>created\_at,</p><p>updated\_at,</p><p>just\_created (true for new user or false for already exist. </p><p><strong>User must be totally new</strong> in BB! He is old if he start <strong>any</strong> BB bot before)<br><br><strong><code>Can be blank:</code></strong></p><p>first\_name, last\_name, username <br></p>                                                                 |
| chat                                                                 | <p>data for current chat. </p><p></p><p><strong>Fields:</strong> </p><p>id (BB id), </p><p>chatid (telegram chat id), </p><p>bot\_id, </p><p>title, </p><p>chat\_type (can be: "private", "group", "supergroup"), </p><p>user\_id, </p><p>created\_at, </p><p>updated\_at, </p><p>just\_created - <code>true</code> for new (just created) chat or <code>false</code> for already exist</p><p></p><p><strong><code>Note:</code></strong></p><p>BB delete blocked chats after 6 months. If user start blocked bot after 6 months this chat have just\_created field again<br></p> |
| bot                                                                  | <p>data for bot. </p><p></p><p><strong>Fields:</strong> </p><p><code>id</code>, </p><p><code>name</code>, </p><p><code>token</code>, </p><p><code>created\_at</code>, </p><p><code>updated\_at</code>, </p><p><code>csv\_url</code>, </p><p><code>last\_run\_at</code>, </p><p><code>store\_bot\_id</code>, </p><p><code>status</code></p>                                                                                                                                                                                                                                       |
| command                                                              | <p>data for command. </p><p></p><p><strong>Fields:</strong> </p><p><code>id</code>, </p><p><code>name</code>, </p><p><code>folder</code>, </p><p><code>need\_reply</code>, </p><p><code>auto\_retry\_time</code>, <code>last\_auto\_retry\_at</code>, <code>created\_via\_csv\_import</code>, <code>last\_csv\_import\_at</code>, </p><p><code>created\_at</code>, </p><p><code>updated\_at</code></p>                                                                                                                                                                           |
| params                                                               | command parameters - text                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                        |
| owner                                                                | information about bot owner: email, id and etc                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| completed\_commands\_count                                           | the count of previously completed commands on `Bot.runCommand` calls. Can be used for [security](https://help.bots.business/scenarios-and-bjs/bjs-security#use-completed_commands_count-variable)                                                                                                                                                                                                                                                                                                                                                                                |
| iteration\_quota                                                     | current quota information: limit, progress and etc. You can see it by `Bot.sendMessage( inspect(iteration_quota) )`                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| payment\_plan                                                        | current bot owner payment plan information                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| BB\_API\_URL                                                         | api url: api.bots.business. Each Cloud have own Api Url                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          |

###

### You can inspect any variable for debug

```
Bot.sendMessage( inspect(user) )
Bot.sendMessage( inspect(chat) )
```


# Bot functions

| Function                                   | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Bot.sendMessage(text)`                    | <p>Send message to current chat. It is simple method with markdown by default. See <a href="/pages/-LWKOa6_mJs5CxgUHdCu">more</a></p><p></p><p><code>Bot.sendMessage("Hello from bot")</code></p>                                                                                                                                                                                                                                                                     |
| `Bot.runCommand(command, options)`         | <p>Run other command</p><p><code>Bot.runCommand("/contact")</code></p><p><br>and with options: </p><p><code>Bot.runCommand("/contact", {phone: "+15424", email: "<example@example.com>"})</code></p><p><br>in second command /contact:</p><p>Bot.sendMessage("Phone is:" + options.phone);</p>                                                                                                                                                                        |
| `Bot.run(options)`                         | <p>Run other command</p><p>Bot.run({ command: "/contact" })</p><p></p><p><a href="#bot.run-params">see more</a></p>                                                                                                                                                                                                                                                                                                                                                   |
| `Bot.clearRunAfter(options)`               | <p>Clear other command with run\_after by label </p><p></p><p><a href="#bot.clearrunafter-options">see more</a></p>                                                                                                                                                                                                                                                                                                                                                   |
| `Bot.runAll(options)`                      | <p>Run other command for all chats</p><p><code>Bot.runAll({ command: "/broadcast" })</code></p><p></p><p><a href="#bot.runall-options">see more</a></p>                                                                                                                                                                                                                                                                                                               |
| `Bot.sendKeyboard(buttons, message)`       | <p>send keyboard and message. Message is required</p><p></p><p><code>Bot.sendKeyboard("about, help,\ncontacts", "send keyboard now")</code></p>                                                                                                                                                                                                                                                                                                                       |
| `Bot.sendInlineKeyboard(buttons, message)` | <p>Send inline keyboard and message. Message is required. Buttons is array. Button must have text fields: title(required), url or command.</p><p></p><p><code>Bot.sendInlineKeyboard(\[ {title: "google", url: "<http://google.com>" }, {title: "other command", command: "/othercommand"} ], "Please make a choice.")</code></p>                                                                                                                                     |
| `Bot.editInlineKeyboard(buttons)`          | <p>Edit exist inline keyboard after executing the command that was called by its button</p><p></p><p><code>Bot.editInlineKeyboard(\[ {title: "google", url: "<http://google.com>" } ])</code></p>                                                                                                                                                                                                                                                                     |
| `Bot.setProp(name, value)`                 | <p>Set property with name for bot. <a href="/pages/CA4h2VsH9l6J3MNHXvdW#set-property">Read more</a></p><p></p><p><code>Bot.setProp("TotalScore", 100)</code> </p><p><br>Also you can pass type: <code>Bot.setProp(name, value, type)</code></p><p>Type can be: <code>integer, float, string, text, json, datetime</code></p>                                                                                                                                          |
| `Bot.getProp(name)`                        | <p>Read property with name. Name is case sensitive. Name is case sensitive. <a href="/pages/CA4h2VsH9l6J3MNHXvdW#get-property">Read more.</a></p><p></p><p><code>Bot.getProp("TotalScore")</code></p><p></p><p>can get property with default value for non exist property:</p><p><code>Bot.getProp("TotalScore", 100)</code> </p><p><br>can get property of another bot:<br><code>Bot.getProp({ name: "propName", other\_bot\_id: OTHER\_BOT\_ID })</code></p><p></p> |
| `Bot.deleteProp(name)`                     | Delete property by it name                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `Bot.importCSV()`                          | CSV import. More info [here](https://help.bots.business/create-bot-from-google-table)                                                                                                                                                                                                                                                                                                                                                                                 |
| `Bot.blockChat(chat_id)`                   | <p>Block chat:</p><p><code>Bot.blockChat(chat.id)</code></p>                                                                                                                                                                                                                                                                                                                                                                                                          |
| `Bot.unblockChat(chat_id)`                 | <p>Unblock chat:</p><p><code>Bot.unblockChat(chat.id)</code></p>                                                                                                                                                                                                                                                                                                                                                                                                      |
| `Bot.inspect(value)`                       | Send inspected value to chat. Good for debug                                                                                                                                                                                                                                                                                                                                                                                                                          |

**Access to property** in answer:

> You can also use the properties in the command's answer. For example, you can do this with the / hello command:`Total score: <TotalScore>!`

## Bot.run(params)

Run other command

```javascript
Bot.run(params)
```

| Field                  | Description                                                                                                                                                                                             |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `command`              | **Required**. Command for run. For example "/start". Can pass params                                                                                                                                    |
| `options`              | json for passing to command. Available through options in this command                                                                                                                                  |
| `run_after`            | <p>delay in seconds before command callingName is case sensitive.<br><br>can be float. <br><br>Exact execution time is not guaranteed. Command will be executed in background.</p>                      |
| `background`           | Boolean: (true or false). By default: false. If true - command will be executed in background.                                                                                                          |
| `bot_id`               | <p>bot\_id for passing. <strong>By default</strong> this is current bot.id. <br><br>This bot must be in the same BB Account</p>                                                                         |
| `user_id`              | user\_id for passing. **By default** this is current user.id                                                                                                                                            |
| `user_telegramid`      | user\_telegramid for passing                                                                                                                                                                            |
| `chat_id`              | chat\_id for passing. **By default** this is current chat.id                                                                                                                                            |
| `label`                | can be used for clearing with `Bot.clearRunAfter`                                                                                                                                                       |
| `ignoreMissingCommand` | <p>do not throw error if command not found (can be used for some logic with <a href="/pages/-LsWOlRvn5_RXefEJC9L#beforeall-and-afterall-commands">@</a> command and etc).<br><br>By default - false</p> |

**Example 1**. Run another command `/balance` with delay 1 hour for current user

```javascript
Bot.run( {
    command: "/balance",
    run_after: 1*60*60,  // 1 hour delay
    // label: "runBalance"  // label can be used for remove future calling
} )
```

**Example 2**. Run another command `/balance` with delay 5 days for this user

```javascript
Bot.run( {
    command: "/balance",
    run_after: 60*60*24*5,  // 5 days delay
    // options: { amount: 5, currency: "BTC" }  // you can pass data
    // chat_id: chat.id  // or use another chat_id
    user_id: user.id,  // or use another user.id
    // user_telegramid: tgId // or another user's telegram id
    // bot_id: ANOTHER_BOT_ID // to run command for your another bot 
} )
```

## Bot.clearRunAfter(options)

Can clear future command(s) execution setted by Bot.run

{% hint style="info" %}
Use this function if future command calling not needed already
{% endhint %}

```javascript
// delete all future commands executions
Bot.clearRunAfter()
```

```javascript
// delete all future commands executions with label "myLabel"
Bot.clearRunAfter({ label: "myLabel"})
```

| Field   | Description                                               |
| ------- | --------------------------------------------------------- |
| `label` | **Required**. Command for clearing. For example "myLabel" |

**Example 1**. Run another command `/work` with delay 5 days. And remove that delay (for example on 3th day)

```javascript
Bot.run({
    command: "/balance",
    run_after: 60*60*24*5,  // 5 days delay
    label: "myLabel"
})
```

On the third day we learned that the call is no longer needed:

```javascript
// remove all future executions with label "mylabel"
Bot.clearRunAfter({
    label: "myLabel"
})
```

## Bot.runAll(options)

Run other command for all chats

{% hint style="success" %}
Use this command for broadcasting any information: message, photo, video, keyboard and etc
{% endhint %}

{% hint style="warning" %}
**Bot.runAll** works for worked bots only. \
\
If you start a new task **before** the previous old task has completed, there is **no guarantee** that the old task will complete for all chats.

You **need to wait** for the old task to complete before starting the new one.
{% endhint %}

<pre class="language-javascript"><code class="lang-javascript"><strong>Bot.runAll(params)
</strong></code></pre>

| Field       | Description                                                                                                                                                                                                   |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `command`   | **Required**. Command for run. For example "/start". Can pass `params`                                                                                                                                        |
| `options`   | json for passing to command. Available through options in this command                                                                                                                                        |
| `on_create` | run this command on task creation with task information                                                                                                                                                       |
| `for_chats` | <p>Command will be runned for this chats type only. Can be:</p><p><code>"private-chats"</code></p><p><code>"group-chats"</code></p><p><code>"super-group-chats"</code></p><p><code>"all"</code> - default</p> |

**Example**:

Command: `/news`

```javascript
Bot.runAll( {
    // this command will be executed
    // for each private chat (user)
    command: "/broadcast",
    for_chats: "private-chats",
    on_create: "on_new_brodcast_task",
    // you can pass data via options
    options: { news: "Hello! it is news!" }
} )
```

Command: `/broadcast`

```javascript
// it have user and chat object!
// so we can send any information now: message, keyboard, photo and etc

Bot.sendMessage(options.news)

// we can get brodcast info via task
/*
let task = options.task;
Bot.sendMessage(
   "Task progress: " + task.progress +
   "\n total: " + task.total +
   "\n cur index: " + task.cur_position +
   "\n status: " + task.status +
   "\n errors: " + task.errors_count
)
*/
```

Command: `on_new_brodcast_task`

```javascript
const task = options.run_all_task;
Bot.sendMessage(
  "Task for brodcasting created. Task id: " + task.id
);

// save task id:
Bot.setProperty("curBrodcastTaskID", task.id, "integer")

// Bot.inspect(options.run_all_task);
```

Command: `/progress`

```javascript
// show current runAll progress

const taskID = Bot.getProperty("curBrodcastTaskID");
let task = new RunAllTask({ id: taskID });
// Bot.inspect(task) // you can check all fields

if(!task.status){
  Bot.sendMessage("This task not found")
  return
}

Bot.sendMessage(
  "Current brodcast: " + 
  "\n Status: " + task.status + " " + task.progress + "%" +
  "\n Progress:" + task.cur_position + "/" + task.total
)

```


# Message broadcasting and editing

{% embed url="<https://www.youtube.com/watch?v=TBXExlAMD3s>" %}

| Function                  | Description                                                                                                                                                                                                                                                                                                                                                                                                          |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Bot.sendMessage(text)`   | <p>Send message to current chat. It is simple method with markdown by default.</p><p></p><p><code>Bot.sendMessage("Hello from bot")</code></p>                                                                                                                                                                                                                                                                       |
| `Api.sendMessage(params)` | <p>Send message. It is Telegram Bot Api <a href="https://core.telegram.org/bots/api#sendmessage">method</a>. You can pass any params like text, reply\_markup, parse\_mode and etc:<br><br><code>Api.sendMessage({</code><br>   <code>text: "Hello, \<b>World!\</b>",</code></p><p>   <code>parse\_mode: "HTML",</code><br><code>})</code><br><br>By default, chat\_id accord to the current chat. (chat.chatid)</p> |

## Do you want broadcast text to all chats?

See [Bot.runAll](https://help.bots.business/bjs/pages/-LWKOGutkEXBP26aPk-j#bot.runall-options) command &#x20;

## Do you want broadcast photo, video and etc?

See [Bot.runAll](https://help.bots.business/bjs/pages/-LWKOGutkEXBP26aPk-j#bot.runall-options) command

## **Message editing**

| **Function**                        | Description                                                                                                                   |
| ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| Bot.editMessage(value, message\_id) | <p>Simple method for message editing with value and message\_id</p><p></p><p><code>Bot.editMessage("new text", 20)</code></p> |
| Api.editMessageText(params)         | Advanced method for message editing. Please see full description [here](https://core.telegram.org/bots/api#editmessagetext).  |

{% hint style="info" %}
message\_id - it is unique identificator for all chats of this bot.
{% endhint %}

{% hint style="info" %}
We have several methods for editing:&#x20;

`Api.editMessageText`

`Api.editMessageCaption`

`Api.editMessageMedia`

`Api.editMessageLiveLocation` and etc. Please see [here](https://core.telegram.org/bots/api#editmessagetext).
{% endhint %}

### **Message\_id for income messages to bot**

For income messages to bot: use `request.message_id`

#### Example

```javascript
let msg_id = request.message_id;
Bot.editMessage("new text", msg_id);
```

{% hint style="warning" %}
Message\_id - have unique value for all chats of bot. So we have only one message\_id with value "2" and only in one chat.
{% endhint %}

###

### Bot message removing

In this example bot will remove old messages from bot.

in first command:

```javascript
Api.sendMessage({
  text: "Hello!",
  // we going to remove this message after 120 sec
  on_result: "removeMsgAfter 120"
})
```

in command `removeMsgAfter`:

```javascript
// user can run this command manually
if(!options){ return }
if(!options.result.message_id){ return }

// extract time delay
let runAfter = parseInt(params);

// run message removing after "runAfter" minutes
Bot.run({
  command: "removeMsg",
  options: { message_id: options.result.message_id },
  run_after: runAfter // in seconds
})
```

in command `removeMsg:`

```javascript
if(!options){ return }

// remove message
Api.deleteMessage({
  message_id: options.message_id
})

// also you can edit message here, make message forwarding and etc
// you have message_id here - so you can do anything
```


# User functions

| Function                      | Description                                                                                                                                                                                                                                                                                                                                                                                                                     |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `User.setProp(name, value)`   | <p>Set property with name for user. Name is case sensitive. <a href="/pages/CA4h2VsH9l6J3MNHXvdW#set-property">Read more</a></p><p></p><p><code>User.setProp("city", "London")</code></p><p></p><p>You can pass type also: <code>User.setProp(name, value, type)</code></p><p>Type can be: <code>integer, float, string, text, json, datetime</code></p>                                                                        |
| `User.getProp(name)`          | <p>Read property with name. Name is case sensitive. <a href="/pages/CA4h2VsH9l6J3MNHXvdW#get-property">Read more</a></p><p></p><p><code>User.getProp("city")</code><br><br>can get property with default value for non exist property:</p><p><code>User.getProp("city", "London")</code></p><p></p><p>can get property of another bot:</p><p><code>Bot.getProp({ name: "propName", other\_bot\_id: OTHER\_BOT\_ID })</code></p> |
| `User.deleteProp(name)`       | Delete prop by name                                                                                                                                                                                                                                                                                                                                                                                                             |
| `User.addToGroup(group_name)` | <p>Add user to group with group\_name</p><p></p><p><code>User.addToGroup("guests")</code></p>                                                                                                                                                                                                                                                                                                                                   |
| `User.getGroup()`             | Get current user's group                                                                                                                                                                                                                                                                                                                                                                                                        |
| `User.removeGroup()`          | Remove user from current group                                                                                                                                                                                                                                                                                                                                                                                                  |

**Access to property** in answer:

> You can also use the properties in the command's answer. For example, you can do this with the / hello command:`Hello, <UserRole>!`

in BJS:

> And you can use it in `Bot.sendMessage("Hello, <UserRole>")`


# Properties

## Introducing

It is possible to save data in bot. Data can be numeric, text, datetime and etc.

For example:

* Bot can have DailyBonus saved in bot prop (it is global for all bot)
* User can have Balance saved in user prop (it is personall)

{% hint style="info" %}
Properties can be belong for user or for bot.
{% endhint %}

## Types

Properties can be:

* integer, e.g.: `150`
* float, e.g.: `5.5`&#x20;
* boolean: `true, false`
* string, e.g.: `"Hello world"`
* text, e.g.: `"it is very big text ..... 1000 symbols here or more"`
* json, e.g.: `{ any: "data", here: "can", be: {used: true}, with: ["array", "too"] }`
* datetime, e.g: `new Date()`

## Set property

```javascript
// set global prop
Bot.setProp({ name: 'myProp', value: 15 });
 
// set JSON prop for user
User.setProp({
 name: 'BIO',
 value: { email: "test@example.com", age: 10 }
});
```

{% hint style="success" %}

* so for global prop use `Bot.xxx` method
* for user's prop use `User.xxx` method
  {% endhint %}

{% hint style="info" %}
You can use short naming also: `Bot.setProp`, `User.setProp`
{% endhint %}

also you can use old style:

```javascript
 // set global prop
Bot.setProperty("myProp", 15, "float");
```

### Set prop for other user by id

```javascript
 // set global prop
Bot.setProp({
  name: 'otherUserProp',
  value: "test Prop",
  // you can pass other user.id for saving user prop for other user
  user_id: other_user.id
});
```

### Set prop for other user by telegramid

```javascript
 // set global prop
Bot.setProp({
  name: 'otherUserProp',
  value: "test Prop",
  // you can pass other user.id for saving user prop for other user
  user_telegramid: other_user.telegramid
});
```

{% hint style="success" %}
You can set (or read) property via bot\_id and read (or set) it via telegramid. It doesn't matter and it will be the same value.
{% endhint %}

### You can save prop in the List

Please read this [article](/bjs/lists)

## Get property

```javascript
// get global prop
var myProp = Bot.getProp('myProp');
Bot.sendMessage("prop: " + myProp);
 
// get prop for user
var bio = User.getProp('BIO');
Bot.sendMessage("Hello, " + bio);
```

or get prop with default value:

```javascript
// prop by default will be 15
var myProp = Bot.getProp('myProp', 15);
```

{% hint style="info" %}
You can use short naming also: `Bot.getProp`, `User.getProp`
{% endhint %}

### Getting other user's prop:

{% hint style="info" %}
Your bot must have this user
{% endhint %}

```javascript
// get prop for other user
var bio = Bot.getProp({
  name: 'BIO',
  // you can pass other user.id for getting other user prop
  user_id: other_user_id
  // or by telegramid:
  // user_telegramid: other_user_telegramid
});
```

{% hint style="success" %}
You can set (or read) property via bot\_id and read (or set) it via telegramid. It doesn't matter and it will be the same value.
{% endhint %}

###

### Getting other bot prop for current user:

{% hint style="info" %}
Your account must have this bot
{% endhint %}

```javascript
// get other bot prop for cur user
var bio = Bot.getProp({
  name: 'BIO',
  bot_id: other_bot_id  // available via bot.id
  // if needed:
  // user_id: userID // for user's prop
  // user_telegramid: tgID // for user by telegramid
});
```

### Getting other bot prop for other user:

{% hint style="info" %}
Your account must have this bot with this user
{% endhint %}

```javascript
// get other bot prop for cur user
var bio = Bot.getProp({
  name: 'BIO',
  bot_id: other_bot_id  // available via bot.id
  // you can pass other user.id for getting other user prop
  user_id: other_user_id
});
```

## Delete property

```javascript
// prop "myProp" will be removed
Bot.deleteProp("myProp");
```

Then `null` passing to prop's value is delete property also:

```javascript
// prop "myProp" with null value will be removed
Bot.setProp("myProp", null, "float");
```


# Always running commands

Sometimes code execution is always required.

## Master command

This command executed only when there are no others commands or on [updates](https://core.telegram.org/bots/api#update) for Telegram bot.

Use `*` in command name.&#x20;

### All Updates

{% hint style="success" %}
**You can handle** [**updates**](https://core.telegram.org/bots/api#update) **with Master Command**

It is possible via `tgUpdate` [variable](/bjs/variables).
{% endhint %}

For inspect data you can use:

`throw new Error(inspect(`tgUpdate`))`

then go to Error Tab and see data. Now you can use it via `tgUpdate.xxx.yyy`

### **Example**

Command `*`

```javascript
// you can track any message here
if(message&&chat){
   Bot.sendMessage("Sorry, bot don't have this command: " + message);
   return
}

// you can see all updated data by:
// Bot.inspect(tgUpdate);

if(tgUpdate.edited_message?.edit_date){
  // user edited message
  Bot.sendMessage("Text edited to:" + tgUpdate.edited_message.text);
}

// another possible updates in:
// https://core.telegram.org/bots/api#update
```

## BeforeAll and AfterAll commands

Code of this commands executed always before (and after) all others commands codes.&#x20;

**Example.** You need add important alert in all commands. You can create only one BeforeAll command with code `Bot.sendMessage("Important alert")`

For `BeforeAll` command use `@` in command name

For `AfterAll` command use `@@` in command name

{% hint style="danger" %}
Please note. Only BJS for `BeforeAll` and `AfterAll` commands runned. No any answer and keyboard here.
{% endhint %}

{% hint style="info" %}
You can share functions, variables and etc with `BeforeAll` and `AfterAll` commands. It is effective for common code parts.
{% endhint %}

```javascript
// code for @ BeforeAll command
function myName(){
  return "Peter"
}
```

```javascript
// code for /test command
Bot.sendMessage(
  myName()  // result will be "Peter"
)

// myName is defined in BeforeAll command
```

{% hint style="danger" %}
Please note. If you need `*`, `@`, `@@ as command names you can use it in aliases`
{% endhint %}

##


# Error command: "!"

By default we have such error message:

<img src="/files/ORl3EjssFaYRuRYkxzXL" alt="" data-size="original">

You can customize this message. Just create command with name "!"

![](/files/yl6RhMFq2D31onATPlhu)

{% hint style="success" %}
You also can use BJS in error command
{% endhint %}

{% hint style="warning" %}
Your code on error command must be 100% correct. There are no any error message for error command in chat.
{% endhint %}


# Lists

Use Lists to store large amounts of data. List is a quick way to [get](/bjs/lists#getting-data) and [search](/bjs/lists#searching) data. Also list is preferred way for organize [statistics](/bjs/lists#statistics).

List - it is a collection of **properties** or **users**.

Examples:

* history (orders history, transactions, payments history, locations history, etc)
* large price lists
* table of cities with population
* results for [Inline Bot](/bjs/inline-bot)
* referrals list

{% hint style="danger" %}
**Do not use JSON property** to collect a large array. This is a very bad practice.&#x20;

**"Execution timeout"** error - it is typical error if you use JSON prop for large data.

Use a List.
{% endhint %}

## List initialization

Before using the list (new or existing), you need to initialize it.

List can be global for Bot:

```javascript
let list = new List({ name: "MyList" })

Bot.inspect(list.exist) // false for new List, true for already exist list
```

or can be personal for user:

```javascript
let list = new List({ name: "MyList", user: user })

// or for user id
let list = new List({ name: "MyList", user_id: user.id })
```

After it you can perform another list methods

## Create new list

```javascript
// for list saving
if(!list.exist){
  list.create()
}
```

## Remove list

```javascript
list.remove();
```

## Recount list

Recalculate all statistical data in list.

Can spent **5-30 seconds** and more for big list. So you need perform this task on background once in week/day or hour.

```javascript
if (list.isRecountNeeded()) {
    list.recount({
        // this command will be runned after recount
        // onComplete: 'onCompleteListRecount'
    });
}
```

you can get delay time in ms:

```javascript
// total delay in ms
list.recount_delay.total

// need to wait for next recount in ms
list.recount_delay.current_value
```

recount lag:

```
// you can change lag for next recount
// it is 1000 ms by default 
// prefer to use 1000 - 2000
list.recount_delay.lag = 1000; 
```

## Calculate the amount of all props and users

Need [recount](/bjs/lists#recount-list) before

```javascript
list.count;  // integer value
```

## Properties management

### Add bot property to bot list

Bot property can be added to List for bot

{% hint style="success" %}
Example. Bot can have price list.
{% endhint %}

```javascript
Bot.setProperty({
  name: 'product1',
  value: 'Nano Cloud',
  type: 'string',
  list: 'PaidPlans'  // bot list will be created if not exist
});
```

### Add user property to user list

User property can be added to List for user&#x20;

{% hint style="success" %}
Example. User can have Orders list&#x20;
{% endhint %}

```javascript
User.setProperty({
  name: "order125",
  value: { product_id: "product1", price: 28 },
  type: "json",
  list: "Orders",  // bot list will be created if not exist
});
```

### Add user property to bot list

User property can be added to List for bot

{% hint style="success" %}
Example. Bot can have top customers list.
{% endhint %}

```javascript
let list = new List({ name: "TopCustomers" })
if(!list.exist){ list.create() }

User.setProperty({
  name: "customer" + user.id,
  value: 20, // total income in USD
  type: "float",
  list: list,
  // you can set this prop for other user also:
  // user_id: other_user.id
});
```

### Reject property

Reject property from list without destroying by prop name

```javascript
list.rejectProperty("stringProp");
```

### Remove property

Reject property from list and destroy it by prop name

```javascript
list.removeProperty("stringProp");
```

### Reject all properties (and all users)

Reject all properties from list

{% hint style="warning" %}
this method reject all properties and all users from list
{% endhint %}

```javascript
list.rejectAll();
```

### Remove all properties (and reject all users)

Remove all properties from list

{% hint style="warning" %}
this method remove all properties and reject all users from list
{% endhint %}

```javascript
list.rejectAll();
```

## Users management

### Add user

```javascript
list.addUser(user);

// or if you have id only
// list.addUser({ id: user.id });
```

### Reject user

Reject user from list

```javascript
list.rejectUser(user);
// or by id
list.rejectUser({ id: user.id });
```

### Reject all users

Reject all users from list

```javascript
list.rejectAllUsers();
```

## Getting data

### Getting props from list

```javascript
let props = list.get();
Bot.inspect(props[0])

/* result will be like:
  {
    "name": "stringProp",
    "value": "Bad Apple",
    "user": {
      "id": null
    },
    "created_at": "2020-11-09T01:46:52.270Z",
    "updated_at": "2020-11-09T01:46:52.270Z"
  }
*/
```

### Getting users from list

```javascript
let users = list.getUsers();
Bot.inspect(users[0])
```

### Paginating

We have pages for data. Data is given page by page from the first page.

One page have 100 items by default.

```javascript
// page 1
let props = list.get();
let users = list.getUsers();

// page 2
list.page = 2
props = list.get();  // getting props from page 2
users = list.getUsers(); // getting users from page 2

// it is possible to change default per page
list.per_page = 10 // 100 by default

// total pages
let total_pages = list.total_pages;
```

###

## User searching

### Getting user by id from list

```javascript
// getting user from list if exist
list.getUser({ id: user.id })
```

### Checking the user's existence in the list

```javascript
list.haveUser(user)

// or by id:
list.haveUser({ id: user.id })
```

## Statistics

Is available for integer and float props

Need [recount](/bjs/lists#recount-list) before

```javascript
list.count  // total props + users count

```


# Migration from properties to list

For example you have such old code. Saving product in price list:

```javascript
// we have array with products prices
var priceList = Bot.getProperty("priceList")
if(!priceList){ priceList = [] }

var curProduct = { name: 'Apple iPhone 25', price: 5100 }

// we store all products in property priceList
Bot.setProperty("priceList", priceList, "json")
```

And we can get products from list now:

```javascript
Bot.sendMessage(priceList[0].name + ":" + priceList[0].price)
```

This code is good for small priceList. But is very bad for large count of products (more then 200-500).&#x20;

**So we need migrate it to Lists**

Saving product in price List:

```javascript
Bot.setProperty({
  name: 'Apple iPhone 25',
  value: 5100,
  type: 'float',
  list: 'priceList'  // bot list will be created if not exist
});
```

And we can get sorted top list now:

```javascript
let list = new List({ name: "priceList" })

let products = list.get();  // get first 100 (by default) products

Bot.sendMessage(products[0].name + ":" + products[0].value)
```

Get next 100 products:

```javascript
// get next 100 products:
let list = new List({ name: "priceList" })
list.page = 2;
let products = list.get();  // get first 100 (by default) products

Bot.sendMessage(products[0].name + ":" + products[0].value)
```


# Api functions

Api functions it all functions from <https://core.telegram.org/bots/api>

You can use it with BJS.&#x20;

### **Example 1.** Send audio to current chat

```javascript
Api.sendAudio({
  audio: "https://www.bensound.org/bensound-music/bensound-funnysong.mp3"
});
```

send audio to other chat:&#x20;

```javascript
Api.sendAudio({
  chat_id: 5515411,
  audio: "https://www.bensound.org/bensound-music/bensound-funnysong.mp3"
});
```

You can pass allowed parameters. For example for [sendAudio](https://core.telegram.org/bots/api#sendaudio) it can be title and disable\_notification

```javascript
Api.sendAudio({
  audio: "https://www.bensound.org/bensound-music/bensound-funnysong.mp3"
  title: "test audio",
  disable_notification: true
});
```

### **Example 2.** Send photo with inline keyboard

![](/files/-LneMI_hD-CuoEzEZW1J)

```javascript
// see all parameters in https://core.telegram.org/bots/api#sendphoto
Api.sendPhoto({
  photo: "https://cataas.com/cat", // it is picture!
  caption: "Test photo",

  reply_markup: { inline_keyboard: [
    // line 1
    [
      // open the link on button pressing
      { text: "button1", url: "http://example.com" },
      // run command /onButton2 on button pressing
      { text: "button2", callback_data: "/onButton2" }
    ],
    // line 2
    [
       // see all params in
       // https://core.telegram.org/bots/api#inlinekeyboardbutton
       { text: "button3", callback_data: "/onButton3" }
    ]
  ]}
});
```

## Get methods

You can call Api get methods (and others methods too). Need pass `on_result` key.&#x20;

For example get all user's profile photos:

#### Command `/get`

```javascript
Api.getUserProfilePhotos({
    user_id: user.telegramid,
    // this command will be executed after getting photos
    on_result: "onGetProfilePhotos",
    // you can pass any options for callback:
    // bb_options: { your: "any", options: "here" }
});
```

####

#### Command `onGetProfilePhotos`

```javascript
// you can inspect result:
// Bot.inspect(options) 

if(!options.ok){
   return Bot.sendMessage("Error!");
}

if(options.result.total_count==0){
   return Bot.sendMessage("You have no photos in profile")
}

let photos = options.result.photos;
for(let i in photos){
   Api.sendPhoto( { photo: photos[i][0].file_id } );
}

// and passed bb_options:
// Bot.inspect(options.bb_options)
```

## Error handling

It is possible to capture error with `on_error` param

```javascript
Api.sendAudio({
  audio: "https://www.bensound.org/bensound-music/bensound-funnysong.mp3",
  on_error: "/on_error",
  // you can pass any options for callback:
  // bb_options: { your: "any", options: "here" }
});
```

In command `on_error`:

```javascript
Bot.sendMessage("We have error with sending audio");
Bot.inspect(options)

// and passed bb_options:
// Bot.inspect(options.bb_options)
```

### Call any method

For new methods you can use this:

```javascript
Api.call(
  methodName,  // for example "sendMessage" or any new method
  {
    ... params // you can pass any options here
    user_id: user.telegramid,
    // this command will be executed after getting photos
    // on_result: "onGetProfilePhotos",
    // you can pass any options for callback:
    // bb_options: { your: "any", options: "here" }
   }
);
```


# BB Admin functions

## BBAdmin.attractUser

| Function                       | Description       |
| ------------------------------ | ----------------- |
| `BBAdmin.attractUser(options)` | Attract new user. |

Bot owner attract new user with email "<test@example.com>" to Bots.Business. Email must be valid.&#x20;

* User will be received email with password and information for start.
* Bot owner can see new user in App -> Account -> Attracted Users List
* Bot owner have rewards for each attracted user with paid Plan

{% hint style="info" %}
This function work only for new users. For old users - no any attraction and no email.
{% endhint %}

```javascript
BBAdmin.attractUser(
  { email: 'test@example.com'}
)
```

Also it is possible pass owner\_id (If not defined - used bot owner ID)

```javascript
BBAdmin.attractUser(
  { 
    email: 'test@example.com',
    owner_id: user_id // 
  }
)
```

## BBAdmin.installBot

| Function                    | Description                |
| --------------------------- | -------------------------- |
| BBAdmin.installBot(options) | Install bot for other user |

You can install copy of yours exist bot for user with email.

{% hint style="info" %}
If user is new user - they will be attracted as yours referral.
{% endhint %}

{% hint style="warning" %}
You can install only **your** bot for other users
{% endhint %}

{% hint style="success" %}
Bot can be installed as [protected](https://help.bots.business/protected-bot) bot.
{% endhint %}

{% hint style="info" %}
You can pass bot properties for new bot.
{% endhint %}

```javascript
BBAdmin.installBot(
  { 
    // bot will be cloned to this email
    email: 'test@example.com',
    // see bot id in the app -> Bots -> Bot
    bot_id: 15025,
    
    // you can pass bot token if you want
    token: BOT_TOKEN,
        
    // bot can be installed as protected
    // as_protected: true,
    
    // you can pass properties to bot:
    // bot_properties: [
    //     { name: 'test',
    //       value:'hello world',
    //       type:'string' }
    // ]
  }
)
```

{% hint style="info" %}
You can also clone your own bot with this function or use BBAdmin.cloneBot
{% endhint %}

## BBAdmin.cloneBot

| Function                  | Description   |
| ------------------------- | ------------- |
| BBAdmin.cloneBot(options) | Clone own bot |

You can create copy of yours exist bot

{% hint style="success" %}
Bot can be cloned as [protected](https://help.bots.business/protected-bot) bot.
{% endhint %}

{% hint style="info" %}
You can pass bot properties for new bot.
{% endhint %}

```javascript
BBAdmin.cloneBot(
  { 
    // see bot id in the app -> Bots -> Bot
    bot_id: 15025,
    
    // you can pass bot token if you want
    token: BOT_TOKEN,
    
    // run the bot immediately after cloning
    // run_now: true,
    
    // bot can be installed as protected
    // as_protected: true,
    // you can pass properties to bot:
    // bot_properties: [
    //     { name: 'test',
    //       value:'hello world',
    //       type:'string' }
    // ]
  }
)
```


# Admin Panel

**You can create a custom admin panel.**

* make custom data fields: numeric, text, checkbox, password
* data fields will be accessible in BJS
* admin panels can be created via BJS
* bot run customized command on field saving
* supports severals panels with titles and differents fields

**Benefits:**

* making options for saving any api keys, secure and unsecure data
* can run any BJS logic from panel. For example: it will be possible create text field with button "Send this message to all chats" from App.
* make any quick statistic and information. Bot dashboards and etc

![](/files/-Lt3MyvxZezcpNpHPTWM)

## Methods

### Define new Admin Panel

Admin Panel - this is a combination of several panels. Each panel have title, icon, description and one or more fields:

For adding panel:

`AdminPanel.setPanel({ panel_name: PANEL_NAME, data: PANEL_OPTIONS });`

PANEL\_OPTIONS - it is JSON option for this panel

**Example**

![](/files/-LtJWZ1Vl4wcuNbjneOC)

```javascript
var panel = {
  // Panel title
  title: "Admin Information",
  description: "Please fill here your admin id",
  // order index
  index: 0,
  icon: "key",
  // save button title - default "SAVE"
  button_title: "SAVE",
  // command called on saving
  // not necessary
  /* on_saving:{
     command: "/on-saving",
     // if you need user
     user_id: user_id // Get it via Bot.sendMessage(user.id)
  },
  */
  
  // Fields for this Panel
  // here 1 field only
  fields: [
    {
      name: "ADMIN_ID",
      title: "Admin ID",
      description: "you can get your admin_id with BJS Bot.sendMessage(user.id)",
      type: "string",
      placeholder: "your admin id",
      // value: 100,   // default value
      // hidden: true  // if you need hidden field. By default - false
    }
    // another fields here
    // if needed
    // ...
  ]
}

AdminPanel.setPanel({
  panel_name: "AdminInfo",
  data: panel
  // force: true // default false - save fields values
});
```

#### Force

Default is false. All old values for the fields are retained.

If true - all old values for fields are reassigned.

#### Fields

It is array of fields. One panel can have several fields. It is also possible panel without any field.

Fields can have name, value, title, description, type, placeholder and icon

#### Field type

| Type     | Description    |
| -------- | -------------- |
| checkbox | Text input     |
| integer  | Text input     |
| float    | Text input     |
| string   | Text input     |
| password | Password input |
| text     | Text field     |

###

### Getting field value from Panel

{% hint style="success" %}
Use this method for getting one value from panel
{% endhint %}

```javascript
var admin_id = AdminPanel.getFieldValue({
  panel_name: "AdminInfo", // panel name
  field_name: "ADMIN_ID" // field name
})

Bot.sendMessage(admin_id)
```

### Setting field value to Panel

{% hint style="success" %}
Use this method for setting one value to panel
{% endhint %}

```javascript
var result = AdminPanel.setFieldValue({
  panel_name: "AdminInfo", // panel name
  field_name: "ADMIN_ID", // field name
  value: 15236125
})

Bot.sendMessage(result) // true
```

###

### Getting all fields values from Panel

{% hint style="success" %}
Use this method for getting several/all values from panel
{% endhint %}

```javascript
var values = AdminPanel.getPanelValues("AdminInfo");
Bot.inspect(values);
// will be like:
// { ADMIN_ID: 100 }
```

### &#x20;

### Getting panel data

```javascript
var panel = AdminPanel.getPanel("AdminInfo")
Bot.inspect(panel);

// can modify panel
// panel.fields[0].value = 1000
// panel.fields[0].tite = "my admin id"
// AdminPanel.setPanel("AdminInfo", panel);
```

###

### Getting panel field data

```javascript
var panel_field = AdminPanel.getPanelField({
  panel_name: "AdminInfo", // panel name
  field_name: "ADMIN_ID" // field name
})

Bot.inspect(panel_field);
```

### Icons

You can use all icons from [https://ionicons.com](https://ionicons.com/)

## Good practices

{% hint style="success" %}
Use admin panels to create a **configuration**
{% endhint %}

Define Admin Panels in `/config` command with `AdminPanel.setPanel` method.

Then use `AdminPanel.getPanelValue` method for getting any field's value

{% hint style="success" %}
Use admin panels to create a bot **dashboard**
{% endhint %}

Panel without fields can dispay any informations. Use this.

{% hint style="success" %}
Use admin panels to create admin reactions
{% endhint %}

You can launch any bot command on panel saving. It is good for making any admin command execution. Use `on_saving`:&#x20;

```javascript
var panel = {
  // Panel title
  title: "Call secure command",
  description: "It is secure command",
  // order index
  index: 0,
  icon: "key",
  // save button title - default "SAVE"
  button_title: "RUN",
  // command called on saving
  // not necessary
  on_saving: {
     command: "/secure-command",
     // if you need user
     user_id: user_id // Get it via Bot.sendMessage(user.id)
  }
}

AdminPanel.setPanel("SecureCommand", panel);
```


# Send HTTP request

Get page on [example.com](http://example.com)

```javascript
  HTTP.get( {
    url: "http://example.com",
    success: '/onLoading',
    error: '/onError'
    
    // if you need pass headers.
    // By default header "content-type" = 'application/json'
    // headers: { "content-type": null }
    // folow_redirects: true, // if you need folow by redirects
    // background: true - if you have timeout error
  } )

/* also you can send POST, PUT, DELETE, OPTIONS requests:
  HTTP.post( {
    url: "http://example.com",
    success: '/onLoading ',
    body: {},  // body params
    // cookies: "" // cookies
    // headers: { "content-type": null } // - if you need headers
    // folow_redirects: true, // if you need folow by redirects
  } )
*/
```

{% hint style="warning" %}
By default header "content-type" is 'application/json'. Some api may have a bug with this. Try set `headers: { "content-type": null }`
{% endhint %}

{% hint style="success" %}
You can use `GET`, `POST`, `PUT`, `DELETE`, `OPTIONS` methods.\
`Http.post`, `HTTP.put` and etc
{% endhint %}

\
\
Command `onLoading`

```javascript
// downloaded page stored on content field
Bot.sendMessage(content);

Bot.inspect(http_status);   // "200"
Bot.inspect(http_headers);  // headers from response
Bot.inspect(cookies); // it is blank for example.com
```

Command `onError`

```javascript
Bot.sendMessage("Error on downloading");

Bot.inspect(http_status);
Bot.inspect(http_headers);  // headers from response
Bot.inspect(cookies);
```

{% hint style="info" %}
Http request can be performed in background with bigger [timeout](/limitations).
{% endhint %}

Pass `background: true` if you need request from slow web page. Task on backgroud is more slowly but it have bigger timeout limit.


# Web App

With web app you can render web content

## Demo bot

{% embed url="<https://t.me/BBWebAppBot>" %}

## Quickly start

Telegram have [Web Apps](https://core.telegram.org/bots/webapps) now. So BB supports Web Apps too.

{% hint style="danger" %}
**WebApp** is designed for working with HTML, JavaScript, and simple JSON requests. However, if you need to make important changes, such as transferring balances or assigning game points, use [**webhooks**](/libs/webhooks-lib) instead.

🔹 [**Webhooks**](/libs/webhooks-lib) are secure URLs containing a secret key for validation.\
🔹 **WebApp** is not protected—anyone can send any request to it.

Therefore, for critical operations, always use **webhooks** instead of WebApp.
{% endhint %}

It is possible render text (html, css, js, json...) content to web. For example:

```javascript
// command webExample

// get url for Web page
var url = WebApp.getUrl({ 
  command: "webExample",
  // you can pass options
  // options: { any: "options", here: "possible" } 
});

// we can get page url on bot
Bot.inspect(url);

// html content
var content = "<h1>Hello from " + bot.name + "</h1>"

// render this command in web
WebApp.render({ content: content });
```

Go to bot and sent text `webExample`. You will have link to this page:

![](/files/ZkA6UMyxOJSjO8GQ8NA8)

###

### Passing data to BJS

It is possible to pass data from web via url params or via options on `WebApp.getUrl`. For example your url is:

api.bots.business/v2/bots/**BOT\_ID**/**web-app**/**index**?secret=SECRET

you can add data with:

api.bots.business/v2/bots/BOT\_ID/web-app/index?secret=SECRE&#x54;**\&key=value\&another\_key=another\_value**

{% hint style="info" %}
**Please note:**

* You can use any text for key or value
* **key** and **value** must be encoded (it can not have this symbols: " ", "?", "&" and others). You can use encodeURIComponent JS method or another accord your language.&#x20;

{% endhint %}

In BJS you can access to this data via options:

```javascript
let key = options.key
let anotherKey = options.another_key

// or more simple:
// let {key, anotherKey } = options
```

### Templates

It is hard to edit html in Java Script. Templates are a good way to organize your web application.

```javascript
// command index
WebApp.render({
  template: "index.html"
  // you can pass mime type also:
  // mime_type: "text/html", // html by default
});
```

{% hint style="success" %}
Possible [mime types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types): `text/css, text/csv, text/javascript, text/css, text/html, application/json and etc`
{% endhint %}

command "`index.html`":

```html
<!-- it is html template. -->
<html>
  <body>
     <h1>Hello from <%bot.name%></h1>
     <!-- Just calc 2+2 -->
     2 + 2 = <% 2+2 %>
  </body>
</html>
```

You can use bjs tag: `<% your BJS code %>` in this template.

We have:

![](/files/14cRQlC7ayrsQiXWtb66)

#### Passing Variables

{% hint style="info" %}
**Do not use long code** in bjs tag <% %>

It is bad. You can pass any vars to template
{% endhint %}

For example we can pass CSS file and test variable.&#x20;

Command "`index`":

```javascript
// command index
var botLink = "http://t.me/" + bot.name;
var CSSFile = WebApp.getUrl({ command: "renderCSS" })

WebApp.render({
  template: "index.html",
  options: {
    botLink: botLink,
    CSSFile: CSSFile
  }
});
```

command "`index.html`":

```html
<!-- it is html template. -->
<html>
   <!-- // include template app.css -->
   <head>
     <link rel="stylesheet" href="<% options.CSSFile %> ">
   </head>

   <body>
     <h1>Hello from <a href="<% options.botLink%>"> <%bot.name%></a></h1>
     <!-- Just calc 2+2 -->
     2 + 2 = <% 2+2 %>
   </body>
</html>
```

command "`renderCSS`":

```javascript
WebApp.render({ template: "example.css", mime_type: "text/css" });
```

command "`example.css`":

```css
// It is CSS file
body {
    font-family: 'Share Tech', sans-serif;
    font-size: 15px;
    color: white;
    display: flex;
    jsutify-content: center;
    align-items: center;
    margin: 0;
    width: 100vw;
    height: 100vh;
    text-shadow: 8px 8px 10px #0000008c;
    background-color: #343a40;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49' viewBox='0 0 28 49'%3E%3Cg fill-rule='evenodd'%3E%3Cg id='hexagons' fill='%239C92AC' fill-opacity='0.25' fill-rule='nonzero'%3E%3Cpath d='M13.99 9.25l13 7.5v15l-13 7.5L1 31.75v-15l12.99-7.5zM3 17.9v12.7l10.99 6.34 11-6.35V17.9l-11-6.34L3 17.9zM0 15l12.98-7.5V0h-2v6.35L0 12.69v2.3zm0 18.5L12.98 41v8h-2v-6.85L0 35.81v-2.3zM15 0v7.5L27.99 15H28v-2.31h-.01L17 6.35V0h-2zm0 49v-8l12.99-7.5H28v2.31h-.01L17 42.15V49h-2z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E"), linear-gradient(to right top, #343a40, #2b2c31, #211f22, #151314, #000000);
}
 
h1 {
    margin: 40px;
    display: inline-grid;
}
```

Our result now:

![](/files/5NZ48iZ7TMlIkC8YEanU)

## Deployment in Telegram

You can install Web App in [several ways](https://core.telegram.org/bots/webapps#implementing-web-apps)

![](/files/mCStOUzEM4WiKlS5oCAr)

### Inline button

```javascript
var webExample = WebApp.getUrl({ command: "webExample" });

Api.sendMessage({
  text: "🤑 Try our web page",
  reply_markup: { inline_keyboard: [
    [
      // open the any web page on button pressing
      { text: "open Demo Page (from help)", web_app: { url: webExample } },
    ]
  ]}
});
```

### Keyboard button

```javascript
var webExample = WebApp.getUrl({ command: "webExample" });

Api.sendMessage({
  text: "It is example for BB Web App",

  reply_markup: {
    resize_keyboard: true,
    keyboard: [
      // line 1
      [
        { text: "🤑 Open Web App" },
        { text: "Open App", web_app: { url: webExample } }
      ]
    ]
  }
})
```

{% hint style="success" %}
For another ways please see Telegram [Help](https://core.telegram.org/bots/webapps#implementing-web-apps)
{% endhint %}

## **How to?**

**Why Bot.sendMessage method is not working on Web App?**

Bot.sendMessage - it is method for sending message to user in Telegram. The Web App is not a Telegram chat, so there is no user, chat, etc. - anyone can open this web app, the user can share it with other users, etc.

For sending message you need to pass chat id and use something like AJAX request to bot via [Webhook](/libs/webhooks-lib) (it can be more secure) or via another Web App endpoint with [passing data](#passing-data-to-bjs).

**How i can make AJAX requests from my Web App?**

This question is now about web development, not bot development. We have jQuery and other methods, libraries (the list is really long). You can include any external js library in your application and use it. Go to the Internet - there is a lot of information there and our help is not the place where this question should be covered

**How to use BB Libs in Web App?**

BB Libs - it is bot libs not Web app Libs. You can not use libs in Web App<br>

**How to display personal user's data on web page?**

You need to pass this data via url:

```javascript
// command webExample

// get url for Web page
var url = WebApp.getUrl({ 
  command: "webExample",
  // you can pass options
  options: { user: user, chat: chat } 
});

// we can get page url on bot
Bot.inspect(url);
```

So you will have this data in address and can extract it with JavaScript and window\.location.search or etc.

If you want more data or if you need any dynamic content - you can use Webhook to bot (or another WebApp-endpoints) + AJAX requests.&#x20;


# Caching

Commands must be executed quickly within 100 - 250 ms. If commands take a long time to complete, users have a bad impression of using the bot

Some commands cannot be executed quickly:

* HTTP loading
* long api requests (for example, [sendVideo](https://core.telegram.org/bots/api#sendvideo), [getChatMember](https://core.telegram.org/bots/api#getchatmember)- all get methods and etc)
* mass message broadcasting
* Bot.runAll

Some commands can be very large or poorly coded:

* mass properting reading/setting (more then 20 properties in one command
* big (or infinite!) loops
* etc

**if your code runs slower than 300ms - necessary:**

* try to make it more quickly
* or cache it
* or run command on background and cache it (if needed)

{% hint style="danger" %}
If your code takes very long time it will be aborted with timeout error
{% endhint %}

{% hint style="danger" %}
Slow commands can cause your Cloud to **degrade and even crash.**

For example, let's say your cloud can process 1 request per second.

Thus, 4 requests of 250 ms each will be processed per second

But if you have slow commands (let's say one second), the cloud will process only one command instead of four.

Thus, the response to the first message will only be sent in a second. And the answer to the last is the fourth already in four.
{% endhint %}

## Caching methods

### setCache

Example set command caching for 1 hour (for all bot users):

```javascript
Bot.sendMessage("Hello!");

Bot.setCache(
  60*60 // time in seconds 60*60 = 1 hour
)
```

Example of command caching for 1 hour (for one user only):

```javascript
User.sendMessage("Hello, " + user.first_name);

User.setCache(
  60*60 // time in seconds 60*60 = 1 hour
)
```

### clearCache

you can clear Cache (it can be usefull on changing data)

```javascript
Bot.clearCache(
  "/command" // command Name
)
```

clear for user caching

```javascript
User.clearCache(
  "/command" // command Name
)
```

## What can be cached?

Caching is a powerful method for speeding up a bot. But you can't cache everything.

Criteria for caching:

* messages from the bot to this command do not change, or rarely change
* command accepts no params `(/command any param)` or options `(Bot.run(command: "/cmd", options: options))`, or accepts them, but they rarely change
* the result of the command is not critical. Even if the old, not updated value is returned, this is not critical

If your command does not meet these requirements try to devide it for several commands. One or more of them can be cached. To run them use methods: `Bot.run` or `Bot.runCommand`

## &#x20;Advanced techniques

You can PRE run caching in background for long command.

Command `/start`

```javascript
Bot.sendMessage("Welcome to my bot");

Bot.run({
  command: "/longBackroundTask",
  run_after: 1 // will be runned in background after 1 sec
})
```

Command `/longBackroundTask`

```javascript
// make your long task here...
Bot.getProperty("myJSON_1");
Bot.getProperty("myJSON_1");
// ... and etc...
Bot.getProperty("myJSON_100");

User.setCache(
  60*60*24*7 // time in seconds - 60*60*24*7 it is week
)
```

## Examples

command `/time`:&#x20;

```javascript
var date = new Date(); 

var time = "Time: " + 
   + date.getHours() + ":"  
   + date.getMinutes() + ":" 
   + date.getSeconds();

Bot.sendMessage(time);
```

We have such result (without caching) - take 250 ms:

![](/files/-MEMQs1dRY8vvespNaEu)

Edit command for caching:

```javascript
var date = new Date(); 

var time = "Time: " + 
   + date.getHours() + ":"  
   + date.getMinutes() + ":" 
   + date.getSeconds();

Bot.sendMessage(time);

Bot.setCache(120);  // caching for 120 seconds
```

Now we have such result - take 120 ms (instead 250 ms without caching):

![](/files/-MEMZKRsXTmvyL87PJ9y)

Command result is changed only after 120 seconds. During that 120 seconds answer is same.


# Inline Bot

We have [Inline bots](https://core.telegram.org/bots/inline) in Telegram:

[![](https://core.telegram.org/file/811140995/1/I-wubuXAnzk/2e39739d0ac6bd5458)](https://core.telegram.org/file/811140995/1/I-wubuXAnzk/2e39739d0ac6bd5458)

> Beyond sending commands in private messages or groups, users can interact with your bot via [**inline queries**](https://core.telegram.org/bots/api#inline-mode). If inline queries are enabled, users can call your bot by typing its username and a query in the **text input field** in **any** chat. The query is sent to your bot in an update. This way, people can request content from your bot in **any** of their chats, groups, or channels without sending any messages at all.

{% hint style="warning" %}
To enable this option, send the `/setinline` command to [@BotFather](https://telegram.me/botfather) and provide the placeholder text that the user will see in the input field after typing your bot’s name.
{% endhint %}

{% hint style="success" %}
See example bot [BBHelpBot](https://t.me/bbhelpbot)
{% endhint %}

## Support with BJS - command /inlineQuery

Need create command `/inlineQuery`. Such a name is required.

```javascript
// result.query - it is query from inline searching
if(!request.query){ return }

results = [];
totalResult = 0;

// it is array of results.
// we have InlineQueryResultArticle
// core.telegram.org/bots/api#inlinequeryresultarticle
// another types: https://core.telegram.org/bots/api#inlinequeryresult

results.push({
  type: "article",
  id: totalResult,
  title: "Text for item",
  input_message_content:
     { "message_text": "This message will be in chat" }
})

Api.answerInlineQuery({
  // see another fields at:
  // core.telegram.org/bots/api#answerinlinequery
  inline_query_id: request.id,
  results: results,
  cache_time: 30000 // cache time in sec
})
```


# BJS Security

BJS is very powerful and flexible. But with this. But simply make the code **vulnerable**.

{% hint style="danger" %}
Please read this article carefully

Especially if you work with payments, user balances, sell goods through a bot
{% endhint %}

## Any user can execute any command

Vulnerable command `/setBalance`:

```javascript
// admin can add 100$ to users's balance by it telegramid

tgID = params

let res = Libs.ResourcesLib.anotherUserRes("money", tgID);
res.add(100)
Bot.sendMessage("Added 100$ for user");
```

{% hint style="danger" %}
Any user can run /setBalance \[telegramid]
{% endhint %}

So need check execute this command only for admin:

**1.Add this command to** [**group**](https://help.bots.business/commands/groups)

![](/files/-LkCFmOYXniB9GaIUXSU)

add admin to group "admin":&#x20;

```javascript
// create any temporary command with this code
// run it for admin

// destroy command after for security
// also you can protect this command with password

User.addToGroup("admin")
```

**2. Or you can check admin in BJS**

first you need get ADMIN\_TELEGRAM\_ID

```javascript
Bot.sendMessage(user.telegramid)
```

security command:

```javascript
if(user.telegramid!=ADMIN_TELEGRAM_ID){
  return // exit from BJS
}

// ONLY admin can add 100$ to users's balance by it telegramid

tgID = params

let res = Libs.ResourcesLib.anotherUserRes("money", tgID);
res.add(100)
Bot.sendMessage("Added 100$ for user");
```

## Any user can execute any "SECRET" command

For example, you have command `/payment` (have "Wait for answer") with execute other "secret" command `/setBalance` :

```javascript
// command /payment

// user provide oneTime password. If password is valid - add bonus 100$

var oneTimePassword = User.getProperty("oneTimePassword");

if(!oneTimePassword){
  return // we have not oneTime password now
}

if(oneTimePassword=="already taked"){
  // if taked already - exit
  return
}

if(oneTimePassword!=message){
  // user do not know oneTime password
  Bot.sendMessager("Error. Password is wrong")
}

if(oneTimePassword==message){
  // user know oneTime password!
  // make it "already taked"
  User.setProperty("oneTimePassword", "already taked", "string")
  // run "secret" command
  Bot.runCommand("/setBalance");
  Bot.sendMessage("Thank you for payment!");
}
```

"Secret" command `/setBalance`

```javascript
let res = Libs.ResourcesLib.userRes("money", tgID);
res.add(100)
Bot.sendMessage("Added 100$ for you");
```

**So user must:**

* run /payment command
* type secret one time password
* after it - "secret" command "/setBalance" will be runned

**Vulnerability: hacker can run /setBalance only and get bonus immediately**

Need to checking that command `/setBalance` was runned only by command `/payment`

one of the methods - pass secret on run command as params:

command `/payment`

```javascript
...
// part of code for /payment

if(oneTimePassword==message){
  ...
  var secret = "GJHURFVJLHF" // use own secret. You can store it in property
  Bot.runCommand("/setBalance");
  Bot.sendMessage("Thank you for payment!");
}
```

{% hint style="danger" %}
Do not use "GJHURFVJLHF" secret!&#x20;

It is not secret world already: hacker can read this doc too!
{% endhint %}

command `/setBalance`

```javascript
if(params=="GJHURFVJLHF"){
   let res = Libs.ResourcesLib.userRes("money", tgID);
   res.add(100)
   Bot.sendMessage("Added 100$ for you");
}else{
   Bot.sendMessage("You are hacker!")
}
```

## User can run secret command on group chat

It can be accidentally or deliberately provoked by a hacker.

If you have a secret command with a secret result, do not run it in a group chat:

```javascript
// send this link only in PM - secure reason
if(chat.chat_type!="private"){
  return
}
```

## Recommendations

### Do not share your bot token, BB API Key

Bot token and BB API Key - are is very vulnerability data. Do not share theys anywhere!

### Avoid using safe data in protected bot

See full article [here](/protected-bot)

###

### Do not share your BB Bot ID

This can sometimes be unsafe.

### Do not use default command names "/onIncome", "/onTransaction" for important commands

Hacker can brute force such command names and try to execute it

### **Remove /test command**

If you have any /test command with non security BJS - remove it.

Hacker can execute /test too

### Use `completed_commands_count` variable

Anybody can run any command. But it is possible make secured sub command.

For example command `/admin`

```javascript
// make admin access here
// ...

Bot.runCommand("/secure")
```

command `/secure`

```javascript
// this command can not be runned by user
if(completed_commands_count==0){ return }

// only via Bot.runCommand, Bot.run or as "on_result"
// your secure code here
// ...
```

## Do not use any non official libs now.

{% hint style="danger" %}
Do not use any non official libs now.&#x20;

* Any lib can run command with options.
* Any libs can read properties (and read your API Keys from other lib)

We have not way to protect this now. Just **not use NON official libs** with CP lib. Well, that now there are no such libraries
{% endhint %}

## Bad practice&#x20;

### User can change nickname

Bad BJS:

```javascript
let admin = "Jon Smith";

if (user.first_name==admin){
  // do admin action here
  ...
}
```

{% hint style="danger" %}
Any user can set any first\_name, last\_name and etc&#x20;

Hacker can change or create account with this field
{% endhint %}

###

### Use eval method with care

You can use eval for calculation

```javascript
// with Wait for Answer

// message from user is: 2+2
// eval - it js execution from string
let result = eval(message);

// 2+2 = 4. So we have 4 in result now
Bot.sendMessage(result)
```

With such code you can make math calculator.&#x20;

But it is very danger! User can run anything!

For example, user can pass BJS code:  `bot.token`. And bot will send your bot token!

## See BB reports

[Read info](https://help.bots.business/bb-inspection) about BB report. Demo report have nice recommendations.&#x20;


# Good coding practices

## Use Libs

BB have good [libs](/libs/what-it-is-libs). Just install needed library to your bot.

{% hint style="warning" %}
Don't install unnecessary libraries. Your bot might be slow after that.
{% endhint %}

## Use folders

You can organize your commands in folders.&#x20;

![](/files/lYk1igfoM4nj1mQcu2GF)

You can use folder in BJS too. For example in [before All](/bjs/always-running-commands#beforeall-and-afterall-commands) command:

```javascript
// Before all command - @

// set your ADMIN_ID here
// you can get it via Bot.sendMessage(user.id)
var isAdmin = ( user && (user.id == ADMIN_ID) )

if(!command){
   return
}

if((command.folder=="Admin Panel")&&(isAdmin){
  // only admin can run command from Admin Panel's folder
  // any common bjs here for admin
  Bot.sendMessage("Hello, admin!")
}else{
  Bot.sendMessage("Access denied");
  return // exit from command now
}

// other example
if(command.folder=="Under development"){
  Bot.sendMessage("Sorry this command on development")
}
```

## Use good names

Do you have children.

Two boys and one girl. You do not call them b1, b2 ang g1, are you not ?

So why do you call your variables like that?

**Bad examples:**

* x1
* y2
* d3

**Good:**

* currentLimit
* maxCount
* userName

## Use simular names!

![](/files/-MBM_KtAO04fro0IUVts)

## Use JSON property

**Bad code:**

![](/files/-MBM_RI9O_8FdcvO4BNI)

**Good code:**

![](/files/-MBM_Sxyn05xQgTLF5SO)

## Do not use many methods of getProperty or setProperty

**Bad code:**

![](/files/-MBMaOqLc_u7bQEpT-hm)

{% hint style="warning" %}
Each getProperty method spent above 10-100 ms for execution. So if you have 10 getProperty methods bot can spent above 1 sec for execution! It is slowly
{% endhint %}

**Use JSON type:**

![](/files/-MBMbI9-I7IR3CUSGQhR)

## Use functions!

Do not repeat youself!

Bad code:![](https://telegra.ph/file/31bc228cf1f6f793ff034.png)

![](/files/-MBM_crhAHxmI65if5iu)

Good code:![](https://telegra.ph/file/aa3021f92fbd73e5c9ede.png)

![](/files/-MBM_YJoBmWUTjmcf4hV)


# Top errors

## 1. Cannot read properties of null

The `Cannot read properties of null` error occurs when you try to access a property or call a method on a value that is `null`. Since `null` represents the absence of any object value, trying to access properties or methods on it will result in this error.

**Accessing a Property of `null:`**

```javascript
let product = null;
// Error: Cannot read properties of null (reading 'tirle') here:
Bot.sendMessage(product.title);

```

Calling a Method on `null:`

```javascript
let data = null;
// Error: Cannot read properties of null (reading 'toString')
Bot.sendMessage(data.toString());

```

### **How to Fix It**

**Check for `null` before Accessing Properties or Methods** Before attempting to access properties or methods, you should verify that the variable is not `null`.

```javascript
let product = null;
if (product) {
    Bot.sendMessage(product.name);
}
```

**Use Optional Chaining**

Optional chaining provides a concise way to handle `null` or `undefined` values. If the value is `null` or `undefined`, it will return `undefined` instead of throwing an error.

```javascript
let product = null;
Bot.sendMessage(product?.title);
```

{% hint style="warning" %}
We can have null user, chat in [BeforeAll](/bjs/always-running-commands), Master commands, webhook and etc. so you need to check this too.
{% endhint %}

## 2. JS syntax error

### **Common Causes and Recommendations**

Syntax errors in JavaScript occur when the code does not follow the correct syntax rules of the language. These errors prevent the code from executing and typically happen due to simple mistakes. Here are some common causes and tips to avoid them:

1. **Missing or Misplaced Brackets**
   * **Cause**: Forgetting to close curly braces `{}`, square brackets `[]`, or parentheses `()`.
   * **Recommendation**: Always ensure that every opening bracket has a corresponding closing bracket. Tools like linters or code editors with syntax highlighting can help spot these errors.

```javascript
if (condition {
    // code block
} // Missing closing parenthesis and curly brace
```

2. **Unterminated Strings**

* **Cause**: Forgetting to close a string with a quotation mark.
* **Recommendation**: Make sure every string that starts with a single `'`, double `"`, or backtick `` ` `` quote has a corresponding closing quote.

```javascript
let message = "Hello World; // Missing closing quote
```

3. **Using Reserved Keywords**

* **Cause**: Trying to use reserved keywords like `class`, `return`, or `if` as variable names.
* **Recommendation**: Avoid using reserved keywords as identifiers in your code.

```javascript
let return = 5; // Invalid variable name
```

4. **Missing Semicolons**

* **Cause**: Forgetting to add a semicolon `;` at the end of a statement can sometimes lead to unexpected results.
* **Recommendation**: While JavaScript often automatically inserts semicolons, it's good practice to manually add them to avoid subtle bugs.

```javascript
let x = 5
let y = 10 // Missing semicolons may cause issues
```

5. **Uninitialized Variables**

* **Cause**: Using a variable before declaring it.
* **Recommendation**: Always declare variables using `let`, `const`, or `var` before using them in your code.

```javascript
Bot.sendMessage(name); // ReferenceError: name is not defined
let name = 'John';
```

6. **Incorrect Operator Usage**

* **Cause**: Mixing up assignment `=` with equality `==` or strict equality `===`.
* **Recommendation**: Use `=` for assignments and `==` or `===` for comparisons. Prefer `===` for strict equality checks.

```javascript
if (x = 5) { // Mistakenly used assignment instead of comparison
    // Always true, since x is assigned 5
}
```

## 3. Prop size is limited. #WholeUsers issue

{% hint style="danger" %}
We have limit on data saving on prop. It is approx 10K.

So if save much more data your code will be broken.
{% endhint %}

Bad code examples:

```javascript
var fullBotUsers = Bot.getProperty("wholeUsers")
for (var index in fullBotUsers) {
  var info = fullBotUsers[index]
  // other logic here
  // ...
```

or:&#x20;

<figure><img src="/files/9nBftkdZzd0BWZWWJHsL" alt=""><figcaption></figcaption></figure>

and etc.

### How to Fix it

Remove this code. Use [Bot.runAll](/bjs/message-broadcasting#do-you-want-broadcast-text-to-all-chats) for broadcasting or use [List](/bjs/lists) or another logic.

## 4. Can not edit/remove message

On message editing, removing we can have this error.

It is possible on:

* chat was deleted already (user can delete chat with bot in any time). So it is not possible to edit or remove old message if chat deleted
* bot is restricted on chat and can't edit/remove message. Check bot permissions
* message\_id is incorrect - check it
* chatid is incorrect - check it (you need to use chat.chatid not chat.id)
* it is not possible edit message with same text. Use another text for editing
* Text for editng can be very big - check this

## 5. Incorrect file for sending.

If you want to send video with Api.sendVideo or photo with sendPhoto and etc - you need to use direct file link.&#x20;

Incorrect links examples:

* YouTube video link - it is web page with video. Not just video
* Message link with video or with picture. It is message
* incorrect file format. For example, Telegram don't support SVG or something video specific formats

## 6. JSON parsing error: Unexpected Token in JSON

Check that your data is JSON before

You can have here:

* html page not JSON. If you use external Api this Api can response with html on errors.
* blank text
* something else

If you use JSON.parse() method you need check that it is really json data before parsing. &#x20;


# Git

![](/files/-LZsx6pWoRgaf7g74dm-)

## Git support

* Bot exporting to external Git repository. For example, Github
* Bot importing from external Git repository

## Requirements

#### 1. Need set Git repository on bot

Go to Bot->Edit-> show Advanced&#x20;

or:

Go to Bot -> Tools section -> Git sync

![](/files/-LZsyAVym85wy-JGNaEx)

#### 2. Need set Deploy Key on external repository

{% hint style="success" %}
You do not need Deploy Key for read access of public repository&#x20;
{% endhint %}

Go to Bot-> Sync in menu, then Git Sync -> Deploy Key show

![](/files/-LZszSBi4XIsdiAHzM0d)

**Copy Deploy Key**

Now you need set this Deploy Key on external repository.

**Github**

Please see [this](https://developer.github.com/v3/guides/managing-deploy-keys/#deploy-keys). For Git exporting also need "write" access.

#### 3. Now you can make exporting or importing with Git


# Import bot from Git repository

{% embed url="<https://www.youtube.com/watch?v=tCLsrJrMl6E>" %}

## Preconditions

Please see [this](https://help.bots.business/git#requirements) before. (Need set repository and Deploy Key in external repository)

## Importing

{% hint style="danger" %}
All existing bot's commands will be deleted
{% endhint %}

{% hint style="danger" %}
All existing bot's libs will be uninstalled
{% endhint %}

Go to bot -> Sync

![](/files/ziIIzyM43s74xflnVjMm)

Press button "Import from Git rep"


# Export bot to Git repository

{% hint style="success" %}
You can make export for any free bot in the Store. Just install it.
{% endhint %}

## Preconditions

Please see [this](https://help.bots.business/git#requirements) before. (Need set repository and Deploy Key in external repository)

## Exporting

Go to bot -> Sync

![](/files/06fEqEVWOaOxvWvOXYDL)

Press on button "Export to git rep" and wait.

After some minutes new branch with name "BB\_Export\_TIME" will be created on your external repository.&#x20;

## Video by Community

[How to export to Github](https://www.youtube.com/watch?v=07MYMPAVT4c\&ab_channel=Kp%27sSpecials)


# Repository structure

{% hint style="success" %}
You can make export for any free bot in the Store. Just install it.&#x20;

It is good for practice.
{% endhint %}

### bot.json file

Please see [this](https://help.bots.business/git/file-bot-json)

### Commands - in commands folder

File name - it is command name (But it can be rewritten in command description)

{% hint style="warning" %}
For commands with "/" (for example command "/start") file name is "\_start"
{% endhint %}

Command can have: `name`, `help`, `aliases` (second names), `answer`, `keyboard`, `scnarios` (for simple logic) and other options.

{% hint style="success" %}
If the command has a folder - it is located in a folder on the disk with the same name
{% endhint %}

#### Command description

It is optional file header:

```javascript
/*CMD
  command: /test
  help: this is help for ccommand
  need_reply: [ true or false here ]
  auto_retry_time: [ time in sec ]
  folder: MyFolder
  answer: it is example answer for /test command
  keyboard: button1, button2
  aliases: /test2, /test3
CMD*/
```

{% hint style="info" %}
Command description - it is optional block.
{% endhint %}

multiline also supported. For example for answer:

```javascript
/*CMD
    <<ANSWER
test answer
with several
lines
  ANSWER
CMD*/
```

{% hint style="info" %}
You can have only answer (or others) key in the command description. All keys - optional
{% endhint %}

See [more](https://help.bots.business/commands)

#### Command body

It is command code in JavaScript. Use Bot Java Script for logic in command.

For example:

`Bot.sendMessage(2+2);`

See [more](https://help.bots.business/scenarios-and-bjs)

### Libraries - in libs folder

You can store common code in the libs folder

See [more](https://help.bots.business/git/library)


# File: bot.json

bot.json - it is file with bot description. It is required for bot import.

bot.json example:

```
{
  "bb_sync_version":"1.0",
  "name":"testBot",
  "git_remote":"git@github.com:bots-business/bb-bot-test.git",
  "csv_url":"https://example.com/csv"
}
```


# Automatic importing on Git push

ou can make automatic bot deploying on git push.&#x20;

This possible with [Webhooks](https://help.bots.business/libs/webhooks-lib). Make install for this lib.

## Setup

command `/setupGit`

```javascript
var url = Libs.Webhooks.getUrlFor(
   { command: "onGitPush", user_id: user.id }
)

Api.sendMessage({
  text: "Github webhook: " +
     "\n<pre>" + url + "</pre>",
  parse_mode: "html",
  disable_web_page_preview: true
})

Bot.sendMessage(url);
```

execute `/setupGit` copy url and go to Github.com > your repository -> Settings -> Webhooks. Press button "Add webhook"

Past copied url as Payload URL

![](/files/1tmLGDH6b1SytdgRw0jy)

Make like this:

![](/files/94Cd58G25H4twVWIRxPx)

Go to App - create command `onGitPush`

```javascript
Bot.sendMessage("Start code importing...");

// Bot.exportGit also possible
Bot.importGit({
  branch: "master", // it is master branch
  success: "onGitImportCompleted"
})
```

command `onGitImportCompleted`

just put to answer: "Git import completed"

{% hint style="warning" %}
Commands `onGitPush and onGitImportCompleted`must be in repository also. Because all commands will be deleted on git importing
{% endhint %}

{% hint style="danger" %}
Protect onGitPush command if you need this. Anybody can run it.&#x20;
{% endhint %}


# Iterations. How to reduce theys?

All iterations on Bots.Business are paid. You can choose payment plan with different iterations count.

## What it is - "iteration"?

Each payment plan has its own iteration limit.

**1 iteration it is:**

* income message to bot
* [Bot.runCommand](https://help.bots.business/scenarios-and-bjs/bot-functions)(command) or `Bot.run` in the BJS spent 1 iteration
* `Bot.run` with `run_after` spent 2 iterations (1 upon installation and 1 on execution)
* Pressing the keyboard button
* Pressing the inline keyboard button
* 1 Auto Retry - it is 1 iteration
* 1 received webhook - it is 1 iteration
* **1 chats** in [`Bot.runAll`](https://help.bots.business/scenarios-and-bjs/bot-functions#bot-runall-options) command - 1 iteration
* 1 **sended message** on mass broadcasting - 1 iteration
* **5** **chats** on [Information refreshing](https://help.bots.business/bot-information) (in Bot dashboard) - spend 1 iteration
* **100 incoming messages** in blocked chat with method `Bot.blockChat(chat.id)`

5 iterations it is:

* [CSV import](https://help.bots.business/create-bot-from-google-table) - spend 5 iterations
* Git [import](https://help.bots.business/git/import-bot-from-git-repository)/[export](https://help.bots.business/git/export-bot-to-git-repository) - spend 5 iterations

{% hint style="info" %}
Single command execution - 1 iteration
{% endhint %}

{% hint style="success" %}
Iterations are restored every month. Each payment plan has its own iteration limit.
{% endhint %}

### Extra Points

* If you do not have enough iterations, Extra Points are spent.
* Unused Extra Points remain for the next month.
* You can get Extra Points for 💎 BB Points or [buy them](https://t.me/BotsBusinessAdminBot).

### How to get more iterations?

You can upgrade your Plan, buy Extra Points or order BB Cloud with unlimited iterations.

## How to reduce iterations count?

Reduce income messages to bot:

* remove it from super groups
* remove un useful commands

Reduce Bot.runCommand in BJS

Reduce [Auto Retry](https://help.bots.business/commands/auto-retry) calls

## Beware of endless loops

Use `Bot.runCommand`, `Bot.run`, `Bot.runAll` carefully.&#x20;

**Example 1**

Bad code example. Command `/check`

```javascript
Bot.runCommand("/task")
```

Command `/task`

```javascript
...
Bot.runCommand("/check")
...
```

So we have now scheduled `/task` in `/check`. But /task also have run for `/check`

You will end up in an infinite loop and your iterations **will quickly end**

**Example 2**

Bad code example. Command `/check`

```javascript
Bot.run(command: "/task", run_after: 60*60)  // 1 hour delay


```

Command `/task`

```javascript
...
Bot.runCommand("/check")
...
```

So we have now scheduled `/task` in `/check` with delay for 1 hour. But /task also have run for `/check`

But here we have delay for 1 hour. So we have 1 task per hour (and per user!). Is it good?

No! Because user can run `/check` command several times. For example 6 times in one minute. You will be have 6 background tasks during 1 hour instead of 1 tasks. Also any users can execute this command for several times.

You will end up in an infinite loop and your iterations **will quickly end**

{% hint style="danger" %}
Be very careful with Bot.run methods
{% endhint %}

## Beware of **big** loops

Very bad example:

![](/files/-MciMpg0R1F_NCxPSAF-)

Command `check:`

```javascript
var user = options.result.status
User.setProperty("status", user, "string")
if ((user == "member") | (user == "administrator") | (user == "creator")) {
  Bot.runCommand("join2")
  User.addToGroup("user")
}

if (user == "left") {
  Bot.sendMessage("*⚠️ Not Joined :- @Kjtricks_Official *")
}
```

Command `join2`

```javascript
var channel = "@MyChanell1"
let id = user.telegramid;

Api.getChatMember({ chat_id: channel, user_id: id, on_result: "check2" })
```

\
Command `check2`

```javascript
var user = options.result.status
User.setProperty("status", user, "string")
if ((user == "member") | (user == "administrator") | (user == "creator")) {
  Bot.runCommand("join3")
  User.addToGroup("user")
}

if (user == "left") {
  Bot.sendMessage("*⚠️ Not Joined :- @Kjtricks_Official *")
}
```

and etc!

`join1 > check1 > join2 > check2 > ....  join10 >  check10`

**What is problem?**

* each Api.getChatMember spent 1 - 3 sec for execution
* Bot.runCommand run new BJS immediately!

We have 10 join + 10 check. So it will be 10 - 30 secs per 1 message from 1 user.&#x20;

* On Nano Cloud second user must wait this 30 secs! Also even Business Cloud is completely down!
* each Bot.runCommand burn 1 iterations. We have 20 iterations here!

**Fix**

* Use [MCLib](/libs/mcl)
* Use [Bot.run](/bjs/bot-functions#bot-run-params) with run\_after. It run task in background (Users don't have to wait)
* Do not use Bot.run in chain. It is not good.&#x20;

&#x20;


# Limitations

Each command can be executed only a certain time

| Plan         | Timeout (sec) |
| ------------ | ------------- |
| General      | 5             |
| Start        | 8             |
| PRO          | 12            |
| Business     | 20            |
| Big Business | 25            |

[Http request](https://help.bots.business/scenarios-and-bjs/send-http-request) on background have bigger limits:

| Plan         | Timeout (sec) |
| ------------ | ------------- |
| General      | 15            |
| Start        | 24            |
| PRO          | 36            |
| Business     | 60            |
| Big Business | 75            |


# Cloud

#### What it is BB.Cloud? <a href="#what-it-is-bb.cloud" id="what-it-is-bb.cloud"></a>

BB.Cloud - it is your own server instance.&#x20;

We have **monthly** plans of BB.Cloud:

**Nano, Mini, Start, Pro, Business, Big Business** with different power.

## What is different between BB.Cloud and BB.General?

* BB.Cloud have big iterations
* BB.General - all resources are shared into all non cloud bots
* BB.Cloud - all resources are shared only between your bots

## Monthly Plans and specifications for BB.Cloud

<figure><img src="/files/LWgLGnfZqIvWKAFAzKrt" alt=""><figcaption></figcaption></figure>

| **Cloud**              | **Cost** | **Monthly iterations** |
| ---------------------- | -------- | ---------------------- |
| Cloud.Hobb&#x79;**\*** | $22      | 1 million              |
| Cloud.Nano             | $33      | 2 million              |
| Cloud.Mini             | $55      | 5 million              |
| Cloud.Start            | $99      | 10 million             |
| Cloud.PRO              | $220     | 45 million             |
| Cloud.Business         | $300     | 100 million            |
| Cloud.BigBusiness      | $400     | 200 million            |

<figure><img src="/files/2OdEGP7LBAkiIbJueDW5" alt=""><figcaption></figcaption></figure>

| **Cloud**              | **Approximate iterations:** |             |          |
| ---------------------- | --------------------------- | ----------- | -------- |
|                        | **daily**                   | **minutes** | **COST** |
| Cloud.Hobb&#x79;**\*** | 28 000                      | 20          | $22      |
| Cloud.Nano             | 60 000                      | 45          | $33      |
| Cloud.Mini             | 140 000                     | 100         | $55      |
| Cloud.Start            | 300 000                     | 220         | $99      |
| Cloud.PRO              | 1 400 000                   | 1000        | $220     |
| Cloud.Business         | 3 000 000                   | 2200        | $300     |
| Cloud.BigBusiness      | 6 200 000                   | 4500        | $400     |

Please note: values may differ slightly, both up and down, depending on the bot's response time, the complexity of your commands, etc.

{% hint style="info" %}
\*Cloud.Hobby do not have [brodcasting](/bjs/message-broadcasting#do-you-want-broadcast-text) and [auto retry](/commands/auto-retry) for commands.
{% endhint %}

##

## How does the cloud work?

The cloud consists of 6 components - tasks:

* WEB task (processes requests from telegram)
* BJS-runtime task (process BJS)
* other 4 tasks for command repetition, for performing background tasks and for brodcasting

{% hint style="info" %}
There are only 4 tasks in the Hobby Cloud, not 6.
{% endhint %}

Depending on the tariff plan, the process count changes for WEB and BJS-runtime.

| **Plan**          | **Web processes** | <p><strong>BJS-runtime</strong></p><p><strong>processes</strong></p> |
| ----------------- | ----------------- | -------------------------------------------------------------------- |
| Cloud.Hobby       | 1                 | 1                                                                    |
| Cloud.Nano        | 1                 | 2                                                                    |
| Cloud.Mini        | 2                 | 2                                                                    |
| Cloud.Start       | 6                 | 3                                                                    |
| Cloud.PRO         | 10                | 5                                                                    |
| Cloud.Business    | 20                | 10                                                                   |
| Cloud.BigBusiness | 40                | 20                                                                   |

## **Why we have approximate daily iterations?**

As a rule 1 command execution spent 1 iteration.

For example - `/command1`:

```javascript
Bot.sendMessage("Hello");  // it is take above 100 ms for execution
// Total time: 100 ms
```

and `/command2`:

```javascript
// bot send 10 messages with "Hello"
Bot.sendMessage("Hello-1");  // 100 ms
Bot.sendMessage("Hello-2");  // + 100 ms
Bot.sendMessage("Hello-3");  // + 100 ms
...
Bot.sendMessage("Hello - 10"); // + 100 ms
// Total time: 1000 ms = 1 sec
```

`/command1` and `/command2` spent only 1 iteration. But the second command takes **ten times as long** to execute.

Approx execution time for:

* &#x20;`/command1` is **0.1 - 0.2 sec**&#x20;
* `/command2` is **1 - 1.5 sec**

{% hint style="info" %}
Bot can only **execute one command** at a time on Nano Cloud
{% endhint %}

So in 1 second on Nano Cloud we can run:

* above 5 times /command1 (5 iterations per 1 second)
* 1 time only /command2 (1 iteration per 1 second)

{% hint style="info" %}
So Iterations burns depend from your BJS. So we have approximate daily iterations.
{% endhint %}

## Why is my cloud slowing down?

Please look on `/command1` and `/command2` again

`/command1` - can be runned 5 times in 1 second. **Five users** can run this command in one second&#x20;

`/command2` - can be runned 1 times in 1 second only. **Only one user** can run this command in one second.

Example. 5 users run `/command1` at the same time:

* bot replied to all users within 1-2 seconds&#x20;

5 users run `/command2` at the same time:

* 1 user have answer after 1 second
* 2 user have answer after 2 seconds
* 3 user have answer after 3 seconds
* last user have answer only after 10 seconds!

**How to fix this?**

* Don't use too many Bot.sendMessage, Bot.sendKeyboard and etc in one command
* Don't use too many Bot.runCommand or Bot.run in one command or on chain
* Don't use too many Api.xxx methods

Make small commands. Use background tasks with Bot.run and run\_after

### Other slowdown issues

Unfortunately, bad code can lead to slowdowns. Check out this [example](/iterations.-how-to-reduce-theys#beware-of-endless-loops) and also [this](/iterations.-how-to-reduce-theys#beware-of-big-loops).&#x20;

## **What will happen if my incoming messages exceed the specifications?**

Your bots will run slower. Timeout errors will occur. You need to upgrade your cloud

## **How to determine when it's time to upgrade?**

Look at the Errors tab. If there are a lot of times, this can be a signal.

Contact your admin. It will provide you with complete statistics with graphs.

## How many users can the cloud support?

* 1 user can run 1000 commands per hour
* 1000 users can run 1 command per hour

This is the same use. We have no limit on the count of users.


# Reports

You can see a usage report and a commands report for your bot. Just click to links.

![](/files/-MJixO_oIpgfacLpXxzI)

## Usage report

shows the count of new users, chats, received and sent messages, blocked chats, etc.&#x20;

![](/files/-MJiz1roaaSEr_Cb9pYY)

## Commands report

with this report you can see:

* slowest commands (Average run time option)
* the most used commands (Total calls option)

Command can execute with API, BJS-runtime and in background

API - this is an external API call. For example Telegram API

BJS-runtime - this is the execution of your JavaScript code

Background - this is the execution of Bot.run with run\_after options and another scheduled tasks.

![](/files/-MJj2fYZPzO3q1s4ZBfZ)

{% hint style="warning" %}
Average run time for API must be above 0.1 - 0.5 sec. If your command spends more time you need to optimize it.
{% endhint %}


# Deep Linking - pass any params on Bot starting

You can pass any params on bot starting to BJS with link:

<http://t.me/BOT_NAME?start=PARAMS>

In BJS command `/start`:

```javascript
Bot.sendMessage(params);
```

For example:

<http://t.me/botsbusinessadminbot?start=API_TOKEN>

We pass user's API Token to bot.

```javascript
let api_token = params;
// do anything what you want with this params
Bot.sendMessage("Your api token is: " + api_token)
```


# How to link chat account with BB account?

Linked account is needed for integration. For example, you can transfer BB Points from your chat account to BB Account.

For linking go to Side Menu > Account options:

![](/files/-LbHqfjlxOI64HEAP0Li)

Go to block Linked accounts:

![](/files/-LbHqpIgvQpMk16nKa6_)

Press on button "Add account" and go to BotsBusinessAdminBot.


# BB Inspection

BB Team can make "Security and Code Bugs\&Style" Inspection for your bot.

This inspection is an indicator of the quality of your bot. After verification, you will receive:

* a quantitative rating of your bot from 0 to 5
* inspection document with descriptions of vulnerabilities, bugs and bad code styling. See [example](https://docs.google.com/document/d/16QCbOTo_c02Gra9zBknFAR5zxtFiKSXmcL5_9iA_RAU/edit#)

{% hint style="success" %}
If you buy a bot from a third-party developer, a good rating is a great reason to buy a bot.
{% endhint %}

{% hint style="danger" %}
Do you have paymernts in your bot? Inspection can help you not to lose money
{% endhint %}

## See example inspection

![](/files/-LkHV-D5dcbJUEp3uod8)

See full report by this [link](https://docs.google.com/document/d/16QCbOTo_c02Gra9zBknFAR5zxtFiKSXmcL5_9iA_RAU/edit#)


# Protected bot

Protected bot - it is a bot without access to commands editing and copying.

{% hint style="success" %}
Protected bots - good thing for selling to customers.

Make protected bots with [Admin Panels](https://help.bots.business/scenarios-and-bjs/admin-panel) and sell them
{% endhint %}

**Forbidden for this bot:**

* add new command
* edit and remove commands
* view commands
* change BJS
* make bot copy (via app and BJS)
* git exporting (via app and BJS). Git importing is allowed

**Allowed:**

* Bot token changes
* Bot name changes
* Admin panel: view + changing
* Properties: view + changing
* Errors
* Chats, users

{% hint style="danger" %}
**Security**

Try to remove all secure data in such bot like:

* BB Api key
* Coinpayment api keys
* etc

Strictly **do NOT** use such safe data in `/setup`

It will be avaible in Props Tab!

Also, your secure data can be available in Error Tab. So try don't use safe data in protected bot.
{% endhint %}

## How to create Protected bot?

If you want to sell your bot - just start develop it.

You can [install protected bot](https://help.bots.business/scenarios-and-bjs/bb-admin-functions#bbadmin-installbot) for another users via BJS

Contact the administrator to start selling this bot.


# VS Code Extension

Use this extension for quickly bot development with Bots.Business

Use the Bots.Business VS Code extension to develop and maintain your bots directly from the file system, with automatic synchronization to the Bots.Business platform.

### What this extension does

This version of the extension is **file-first**:

* The bot is downloaded into your workspace as normal files.
* All bot commands live in `commands/**/*.js` – these files are the **source of truth**.
* When you save a file, the extension automatically sends the updated command to Bots.Business.
* You can use all VS Code features (AI assistants, Git, search, refactoring, etc.) on your bot code.

### Installation

You can install the extension from:

* **Visual Studio Marketplace** – search for `Bots.Business` in the Extensions view, or use the direct link from the Bots.Business site.
* **Open VSX** (for VSCodium and compatible editors) – search for `bots-business`.

After installation, reload VS Code if it doesn’t prompt you automatically.

### Requirements

* A Bots.Business account.
* Your **BB API Key** from the Bots.Business app (Profile section).
* VS Code / VSCodium with JavaScript support enabled.

### Connecting VS Code to Bots.Business

1. Open VS Code with any folder as your workspace (it can be empty for a new bot).
2. Open the **Command Palette** (`Ctrl+Shift+P` / `⌘+Shift+P`).
3. Run **`BB:login`** (or **“Bots.Business: Login”** depending on your UI).
4. Paste your **BB API Key** from the Bots.Business Profile page and confirm.
5. Optionally, you can also set the key in VS Code settings:
   * `File → Preferences → Settings → Extensions → Bots.Business`
   * Or directly in `settings.json` via `"bots-business.apiKey"`.

Once the API key is saved, the extension can access your bots.

### Downloading a bot to the file system

1. Make sure you are logged in via `BB:login`.
2. Open the Bots.Business view or run the relevant command from the Command Palette (for example, a bot install / download command).
3. Select the bot you want to work with.
4. The extension will create a local structure in your workspace, including a `commands/` folder with one `.js` file per command.

Each command now appears as a regular JavaScript file in the VS Code Explorer.

### File-first workflow

#### Editing existing commands

1. Open any file under `commands/`, e.g. `commands/start.js`.
2. Change the code as needed.
3. **Save the file** (`Ctrl+S` / `⌘+S`).

On save:

* The extension detects the change.
* The corresponding command is automatically updated on Bots.Business via the API.
* The file in your repository / project remains the primary source.

You can now freely use:

* AI code assistants in VS Code
* Refactoring tools
* Multi-file search and replace
* Git / other VCS tools

#### Creating new commands

There are two main options:

1. **Via extension command (recommended)**
   * Use the Command Palette and run the “new command” action (e.g. `BB:newCommand`).
   * The extension creates a new file in `commands/` with the correct internal metadata.
2. **From a new file**
   * Create a new `.js` file under `commands/`.
   * Use the extension’s command to register / sync this file as a new command (exact command name depends on the current version).
   * After the first sync, the command will exist on Bots.Business and will be linked to this file.

#### Deleting commands

Typical flow:

* Delete the corresponding file in `commands/`.
* Run the relevant extension command or refresh (e.g. `BB:refresh`) so the tree and remote state are updated.

If deletion behavior is critical for your workflow, check current release notes or test on a non-production bot first.

### CMD-blocks and metadata

Each command file contains an internal **CMD-block** – a special comment block with metadata, including the command ID on Bots.Business.

* The CMD-block is used by the extension to match a file to a remote command.
* Do **not** remove this block.
* Do **not** manually edit its contents unless you know exactly what you are doing.

If the CMD-block is broken or removed, the extension may not be able to sync the file with the existing command and can treat it as a different/new command.

### Synchronization rules (summary)

* **Source of truth**: `commands/**/*.js` in your workspace.
* **Direction**: local file → Bots.Business on every save.
* **Initial import**: when you first download a bot, its current commands are written into files.
* **Conflicts**: if you edit commands both in the web UI and in VS Code, the last saved version wins. For consistent workflow, prefer editing through the extension once the bot is file-based.

### Typical quick-start scenario

1. Install the extension from Marketplace/Open VSX.
2. Get your BB API Key from the Bots.Business Profile.
3. Run `BB:login` in VS Code and paste the key.
4. Download a bot into an empty folder.
5. Open `commands/start.js`, change a reply, save the file.
6. Test the bot in Telegram – the reply is updated.

### Troubleshooting

* **Nothing happens on save**
  * Check that you are logged in (`BB:login`).
  * Confirm the workspace contains the bot files and `commands/` folder.
  * Make sure the file is under `commands/` and has a CMD-block.
* **Bot tree looks outdated in VS Code**
  * Use the refresh command (e.g. `BB:refresh`) to reload data from Bots.Business.
* **API errors**
  * Verify the API key is valid and not expired.
  * Check that you still have access to the selected bot in the web interface.

For advanced usage, refer to the extension’s changelog and repository, or test changes on a non-production bot first.

## Links

You can istall extension from the Stores or from VSCode.

{% embed url="<https://marketplace.visualstudio.com/items?itemName=bots-business.bots-business>" %}

{% embed url="<https://open-vsx.org/extension/bots-business/bots-business>" %}


# How to...

## Q: What it is "BJS"?

It is Bot JavaScript. It's an ordinary Java with some inserts.

## Q: I do not know the JavaScript. What should I do?

Usually do not need something complicated for developing bots. You can read a couple of articles about JS: <https://www.w3schools.com/js/js_syntax.asp> or <https://en.wikipedia.org/wiki/JavaScript_syntax>

## Q: How can I get two answers from one command?

You can use bot answer and `Bot.sendMessage("ANY message").`

or use two functions: BJS code:

```javascript
   Bot.sendMessage("ANY message");
   Bot.sendMessage("Other any message");
```

## Q: I have Markdown warning for message in Errors. What it is?

Telegram have markdown for text formating.

samples:

````
\n - new line (multi-line text also allowed)
*bold text*
_ italics _
[text](URL)
`inline fixed-width code`
```text
pre-formatted fixed-width code block
````

So if you have incorrect markdown - you have this warning. Sample text with incorrect markdown:

```
  bot_name
  price 1*
  "user`s" - wrong. Use "user's"!
```

## Q: How I can use inline keyboard?

Please see [demo bot](https://telegram.me/DemoInlineKeyboardBot). It avaible in the Store.

BJS code:

```javascript
var buttons = [
    {title: "Go to Google", url: "https://google.com"},
    {title: "Call command for Button1", command: "/touch Button1" },
    {title: "Call command for Button2", command: "/touch Button2" }
];

Bot.sendInlineKeyboard(buttons, "Please make a choice. After that, another command `/touch` will be started with parameters");
```

`buttons` - it is array. It contains buttons. Each button is object with `title` (required), `url` or `command`.

Button must have `url` or `command`. `url` - any link.

`command` - this command will be executed after button pressing. Can contain parameters through a space. `Command` can not be more then 64 bytes.

## Q: How to bot can send reply for users message

You need pass options parameter with `is_reply`

```javascript
  Bot.sendMessage("It is reply message", {is_reply: true} );
```

For any message in chat use: `reply_to_message_id`

```javascript
  Bot.sendMessage("It is reply message", {reply_to_message_id: request.message_id } );
```

Also you can retry with keyboard or inline keyboard too

```javascript
  // retry for last message
  Bot.sendMessage("It is reply message", {is_reply: true } );
  // or for any message
  Bot.sendMessage("It is reply message", {reply_to_message_id: request.message_id } );

  Bot.sendInlineKeyboard(
      [ {title: "google", url: "http://google.com" }, {title: "other command", commnad: "/othercommand"} ],
      "Please make a choice.",
      {reply_to_message_id: request.message_id }
 )
```

You can retry for any message from chat.

## Q: I do not undestand variables: `request`, `user`, `chat`, and etc.

You can see it with `inspect` function:

```javascript
  Bot.sendMessage( inspect(request) );
  // or 
  Bot.inspect(request)   // if have issue with markdown
```

## Q: I would like to create bjs for time limit! Example in a bot you can use the command only every 24hrs!

BJS code:

```javascript

function canRun(){
  var last_run_at = User.getProperty("last_run_at");
  if(!last_run_at){ return true }
  
  var minutes = (Date.now() - last_run_at) /1000/60;
  
  var minutes_in_day = 24*60
  
  if(minutes < minutes_in_day){
   Bot.sendMessage("Please return later. ")
   return
  }
  return true;
}

if(!canRun()){ return }
User.setProperty("last_run_at", Date.now(), "integer");

// your code here:
// ...
```

## Q: How i can create bjs that if you click button it directs to open a link in web?

Unfortunately, this is not supported by the Telegram API. But you can send link to chat: answer:

```
[Open](http://example.com)
```

## Q: How i can create password access to bot?

You can use a group for commands. Then such commands can be started only by those users who are in this group. You can assign users to a group through BJS with password verification.

*Example* Bot:

> password?

User:

> 12345

Bot:

> Welcome, member!

In this example, the user must enter the correct password. After that, the group `Members` is setted and user can execute all commands of this group. If the password is not correct, a error message is displayed.

**Bot:** answer: `password?` need\_reply: `true`

BJS code:

```javascript
if(message=="12345"){
  User.addToGroup('Members');
  Bot.sendMessage("Welcome, member!");
}else{
  Bot.sendMessage("Password incorrect");
}
```

## Q: Do you know BJS code that bot will automatically message user if they don't do any activity in the bot in a given time?

**1. You can store Last Active time** for user in bot's property:

command `tracking`

> this is an invisible command for users. It is run from other commands only

BJS code:

```javascript
   if(chat.chat_type=="private"){
      // track only private chats

      total_users = Bot.getProperty("total_users");
      if(!total_users){ total_users = 0 }
      Bot.setProperty("total_users", total_users+1, "integer");

      var propLastActiveName = "user" + String(total_users) + "_last_active_at";
      var propChatIdName =  "chat" + String(i) + "_id";

      Bot.setProperty(propLastActiveName, (new Date), "datetime");
      Bot.setProperty(propChatIdName, chat.chatid, "string");  
   }
```

**2. In&#x20;*****others commands*****&#x20;you need call** `tracking` **command** Bjs code:

```javascript
   Bot.runCommand("tracking");
   // your any code here
```

> Please note. This code is needed in all commands of your bot.

**3. Automatically message command.** Set auto retry time for it: 24 hours

BJS:

```javascript
   total_users = Bot.getProperty("total_users");
   for(var i=0; i<total_users; i++){
      var propLastActiveName = "user" + String(i) + "_last_active_at";
      var last_active_at = Bot.getProperty(propLastActiveName);
      var duration = (new Date) - last_active_at;
      var duration_in_minutes = duration / 1000 / 60
      if(duration_in_minutes>60*24){
         // not active more than 24 hours
         var propChatIdName = "chat" + String(i) + "_id";
         var chatId = Bot.getProperty(propChatIdName);
         Bot.sendMessageToChatWithId(chatId, "Hello! How are you?");
      }
   }
```

## Q: Is it possible to put some BJS code in our bot that notify user for cryptocurrency price?

You can use [CurrencyQuote](/libs/currencyquote) Lib

## Q: Is it posible that bot button can have value? How to create like on the screenshot below:

![](https://i.imgur.com/6bA89pW.png)

You must update the keyboard every time the value changes. To do this, send the keyboard with the command. Most likely, this should be done in several commands.

**BJS**:

```javascript
var balance = User.getProperty("balance"); // or your code here
Bot.sendKeyboard(String(balance) + ",\nHelp, Contacts" );
```

{% hint style="info" %}
**Use ResLib for any resources**
{% endhint %}

#### Command `⚡Balance:`

You need create command "⚡Balance:" (without space) or `"⚡"` if you have space beetween "⚡" and "Balance"

**So after button pressing:**

* text "⚡Balance: X BTC⚡" will be sended to chat
* command "Balance:" will be executed
* params "X BTC⚡" will be passed to BJS

## Q: How to set the bot which it result to, when one of the telegram group members click the bot command in telegram bot, the message from the bot only seen by the clickers it self & unseen by another members.

Bot can send message to this user in private. So user need to start this bot in private chat in first.

Then on group chat:

```javascript
Bot.sendMessageToChatWithId(user.telegramid, "BOT ANSWER")
```

Also it is possible show alert message for user in group chat with [answerCallbackQuery](https://core.telegram.org/bots/api#answercallbackquery) after inline button pressing.

## Q: How to get location from user?

User must attach his location to chat.

Need command with "Wait for answer" option (or you can use Master command and catch location)

BJS:

```javascript
// you can inspect all data
// Bot.inspect(request);

let location = request.location
if(!location){
   Bot.sendMessage("Please send location");
   return
}

Bot.sendMessage(
   "Your location is:\n longitude " +
       location.longitude +
       "\n latitude: " +
       location.latitude
 )
```

## Q: I have command with wait fo reply. How to cancel Wait for reply?

Example - command `/askName` have wait for reply. Need to cancel it.

Add keyboard to this command: keyboard "Cancel" (also can be "Back")

BJS:

```javascript
// exit on Cancel or Back button
if((message=="Cancel")||(message=="Back")){
  return // exit
}

// get name here
name = message;
Bot.sendMessage("Hello, " + name);

```

## Q: How to show alert on Inline button pressing?

BJS:

```javascript
Api.answerCallbackQuery({
  callback_query_id: request.id,
  text: "My alert",
  show_alert: true // or false - for alert on top
})
```

## Q: How to check if a user joins a channel?

{% hint style="success" %}
Strongly recommended use [MembershipChecker](/libs/mcl) Lib for this
{% endhint %}

Command: `/isJoined`

```javascript
chanell = "@MyChanell"

Api.getChatMember({
  chat_id: chanell,
  user_id: user.telegramid,
  on_result :"/onCheckJoin"
})
```

Command `/onCheckJoin`

```javascript
let status = options.result.status;

var isJoined = (
   (status == "member")||
   (status == "administrator")||
   (status == "creator")
)

if(isJoined){
   Bot.sendMessage("You are chanell member!");
}else{
   Bot.sendMessage("You are NOT chanell member!");
}
```


# Overview

SmartBot is an advanced class designed for bot developers. It simplifies handling user inputs, managing language translations, and structuring bot commands in a user-friendly way.&#x20;

The class embodies the principles of Bot Smart Architecture, which focuses on logic isolation, multi-language support, and simplicity.

## Key Principles of Smart Architecture

1. **Logic Isolation from Content**: Separates the logic of your bot from its content.
2. **Multi-Language Support**: Defaulting to English, but easily adaptable for other languages.
3. **Unified Command Structure**: Use single commands with multiple translations rather than language-specific commands.
4. **Externalized Text Management**: All texts, especially translatable ones, are kept outside the command code in language files.
5. **Language-Based Elements**: Elements like answers, aliases, and keyboards are defined in language files, not in the command.
6. **Keep It Simple Stupid (KISS)**: One message per command and clarity in command naming.
7. **Command Naming Rules**: Clear and meaningful names for commands.


# Lang File

## Introduction

Language files are a crucial part of developing a multilingual bot using `SmartBot`. They allow you to separate the textual content from the logic of your bot, making it easier to manage and update translations.&#x20;

This guide will walk you through the process of creating and setting up a language file for `SmartBot`.

## Structure

A language file in `SmartBot` is a JSON object that contains keys and values. The keys represent command names, message types, or other identifiers, while the values hold the actual text or translations.

#### Basic Structure

```json
{
  "commands": {
    "/start": {
      "text": "Welcome to our bot!"
    },
    "/help": {
      "text": "Here's how you can use the bot..."
    }
  },
  "types": {
    // General types and templates
  },
  "titles": {
    // General titles or labels used in the commands
    // will be added to params
    // can be accessed via params and via {name} in template
  }
  // Additional sections as needed
}
```

### Rules for Writing Language Files

1. **Do Not Translate Keys**: Never translate the keys in the language file; only translate the values.
2. **Preserve Masks in Curly Braces**: Any text within `{}` should not be translated. These are placeholders for dynamic content.
3. **Avoid Changing the Structure**: Maintain the JSON structure as defined in your bot's code.

### Adding Commands and Responses

Each command your bot can execute should have a corresponding entry in the language file. For example:

```json
"commands": {
  "/start": {
    "text": "Welcome, {username}! Ready to start your journey?"
  },
  "/balance": {
    "text": "Your current balance is {balance} coins."
  }
}
```

### Command Structure in Language Files

In `SmartBot`, the commands section of the language file plays a crucial role. Each command the bot can execute should have a corresponding entry in this section. The structure allows for dynamic content insertion and supports various functionalities like text responses, keyboard layouts, and media handling.

#### Basic Template for Commands

Each command entry can include the following properties:

```json
"commandName": {
  "text": "Response text with {variable}",
  "parse_mode": "HTML",  // default is "Markdown"
  "chat_id": "Chat ID"   // or @channelname",
  "alias": "Command alias",
  "aliases": "Back, Cancel",
  "keyboard": "Button1, Button2",
  "inline_buttons": [
    { "text": "Button text", "command": "/command" },
    { "text": "Button text", "url": "https://link.to" }
  ],
  "alert": "Alert text for inline button",
  "alert_top": "Top alert text",
  "photo": "https://link.to/image.png",
  
  // Run another command
  // you can pass run option
  // "run": { command: "/start", params: { any: "param" } }
  
  // Editing:
  // this command can be act as edit command
  // for text or/and keyboard.
  // Default is: false
  // "edit": false,
  // message id for editing
  // "message_id": "{message_id}",
}
```

#### Key Properties Explained

* **text**: The bot's response text. You can embed variables like `{username}` that will be dynamically replaced.
* **parse\_mode**: Defines how the message text should be parsed and formatted. Defaults to "Markdown".
* **chat\_id**: Specifies where the message should be sent. It can be a user ID, a group ID, or a channel username. By default - it is current chat.
* **alias** and **aliases**: Shortcuts or alternative names for commands. Useful for multi-language support or creating intuitive command names. Examples: "Back, Cancel". Alias support spaces. For example: "Go to back" - it is alias: it is not "Go" with params
* **keyboard** and **inline\_buttons**: Define custom keyboards or inline button layouts for interactive responses.
* **alert** and **alert\_top**: Special properties for displaying alerts when inline buttons are pressed.
* **photo**: Directs the bot to send an image. The URL should point to the image file.
* **run**: you can pass "run" for run sub command like `"run": { command: "/start", params: { any: "param" } }`
* **edit**: A boolean flag indicating whether the bot should edit its previous message instead of sending a new one.
* **message\_id**: message id for editing. Please note: SmartBot passed current message id on inline button pressing automatically&#x20;

#### Example: Simple Test Command

Here's a basic example of a test command setup in the language file:

```json
"/test": {
  "text": "Current language file version: #/langVer"
}
```

#### Using Types and References

You can also use predefined types or templates defined in the `types` section of your language file, as shown in the example above with `#/langVer`.

<pre class="language-json"><code class="lang-json">types: {
  langVer: "Lang file version: 1.0.0",
  // you can structure blocks as you wish - it is just a JS object
  // for example "keyboards", "buttons", "alerts", "screens", "groups" and etc
  keyboards: {
    // we can use it as "#/keyboards/joinInlineKeyboard"
    // "#/" - it is key for types
    // only one button here:
    joinInlineKeyboard: [[
      { text: "Check join to {Joining:notJoinedCount} " + 
          "from {Joining:channelsCount} channel(s)",
       command: "checkJoin"  // it is link for command
    }]]
<strong>  }
</strong><strong>}
</strong></code></pre>

then you can use types in commands:

```json
"/test": {
  // just simnple text with type reference:
  // we used general type "langVer" from "types" section
  text: "#/langVer"
},
```

and as keyboard:

```json
"/start": {
  text: "Hello.\nIt is BB Demo Task Bot." +
    "\n\nYou can earn {currency} for completing tasks.\n\n " +
    "*You need to join:* \n {Joining:allChannels} \n\n",

  // we used general type "joinInlineKeyboard" from "types" section
  inline_buttons: "#/keyboards/joinInlineKeyboard"
}
```

## Setting Up the Language File in SmartBot

To support multiple languages, create separate language files for each language, and then use `SmartBot`'s `setupLng` method to load the appropriate file based on user preferences.

Once your language file is ready, you can set it up in `SmartBot` like this - command name "lng-en":

```javascript
const LANG_EN = {
  // Your English translations...
  "commands": {
    // ...
  },
  "types": {
    // ...
  },
  "titles": {
    // ...
  }
};
smartBot.setupLng("en", LANG_EN);
```

another command - 'lng-fr':

```javascript
const LANG_FR = {
  // Your French translations...
};
smartBot.setupLng("fr", LANG_FR);
```

Setup command - /setup:

```javascript
const languages = [
  // the first language item is default!
  //   it is used if user language is not found
  //   and it is English by default!
  {
    // English
    "name": "English",
    "code": "en",
    "flag": "🇺🇸"
  },
  // add anoter languages here
  // you need also add command lng-CODE e.g. lng-fr
  // use command "lng-en" as template
  // {
  //   // French
  //   "name": "Français",
  //   "code": "fr",
  //   "flag": "🇫🇷"
  // },
  // and etc
];

let cmdName;
for(let i in languages){
  cmdName = "lng-" + languages[i].code;
  Bot.run({ command: cmdName })
}
```

Then run /setup command in the bot.

{% hint style="warning" %}
if you change Lang file you need to rerun `/setup` again
{% endhint %}


# SmartBot

## Introduction

`SmartBot` is a versatile tool designed to enhance bot interaction and management, particularly for multi-language support. This guide focuses on setting up and initializing `SmartBot` for your projects, ensuring a smooth start for beginners in programming.

{% hint style="info" %}
We have bot demo: [BBDemoTaskBot](https://t.me/BBDemoTaskBot) - free available in the Store.&#x20;
{% endhint %}

## Setup

You need setup Lang File. Please read [here](/smart-bot/lang-file)

## Creating an Instance of SmartBot

To use `SmartBot`, you first need to create an instance. This is typically done in the main bot file or where you handle your bot's logic.

#### Syntax:

```javascript
let smartBot = new SmartBot(options);
```

{% hint style="success" %}
You need to put this code:

* in [BeforeAll](/bjs/always-running-commands#beforeall-and-afterall-commands) command - "@"
* and create blank [Master Command](/bjs/always-running-commands#master-command) (because we need to track all commands we need blank "\*" command)
  {% endhint %}

#### Options:

* `params`: Initial parameters for the bot.
* `defaultMarkdown`: The default formatting style for messages (e.g., Markdown, HTML).
* skip\_cmd\_folders: Don't process commands in this folders (it can be "Setup", "Admin" folders for example)
* strict\_params: Default - false. If true - error will be thrown if param not found but it is needed in Command's. It is good for debugging.
* `debug`: A boolean flag for enabling debugging. Default: false.

#### Example:

```javascript
let smartBot = new SmartBot({
  params: {
    balance: 0,
    name: user.first_name
  }
});
```

## Handling Commands

`SmartBot` manages commands based on the language file. Use the `handle` method to process incoming commands and generate appropriate responses.

#### Example:

Prefer to use after all [command "@@"](/bjs/always-running-commands#beforeall-and-afterall-commands):

```javascript
// command "@@"
smartBot.handle();
```

{% hint style="success" %}
You can make "return" in command and[ "@@"-command ](/bjs/always-running-commands#beforeall-and-afterall-commands)will be not run. It can be helpful in some case.
{% endhint %}

### Adding Params

One of `SmartBot`'s key features is its ability to handle dynamic content through variables.

Use the `add` method to include dynamic content in responses:

```javascript
smartBot.add({ username: user.name, balance: user.balance });

// or it can be "set" method
// but with this method all another props will be deleted
// smartBot.set({ username: user.name, balance: user.balance });
```

So we can use username and balance props for command in [Lang File](/smart-bot/lang-file) now:

```json
...
// "/balance" commands
"/balance": {
   text: "Hello, {username}. Your balance: {balance}"
}
...
```

{% hint style="success" %}
Params from options after SmartBot.run (or Bot.run) - are added automatically
{% endhint %}

#### Running other Command

Use the `run` method to execute another command within a command:

```javascript
smartBot.run({
  command: "/anotherCommand"
});

// if you want edit mode:
smartBot.run({
  command: "/anotherCommand edit"
});
```

{% hint style="success" %}
It is same method like Bot.run but current options will be passed automatically
{% endhint %}

### is Alias method

```javascript
let isAlias = smartBot.isAlias(message);

if(isAlias){
  // for example we can have alias "Cancel", "Exit" on button
  // so we just make exit from command
  return
}

// other code
```

### Filling Content

The `fill` method replaces all vars like "{data}" in text with actual variable values:

```javascript
let response = smartBot.fill("Hello, {username}, your balance is {balance}");
```

{% hint style="info" %}
As a rule, there is no need to use this method - everything should happen automatically
{% endhint %}

{% hint style="success" %}
**You can use titles from Lang file like:**

smartBot.fill(smartBot.params.YOUR\_KEY\_FROM\_TITLES)\
\
It is possible because title was added as param
{% endhint %}

## Change language for user

You can change language for user via this code:

```javascript
// change user language to "en"
smartBot.setUserLang("en");
// or to "fr"
smartBot.setUserLang("fr");

// get current user language:
let lngCode = smartBot.getUserLang(); // it will be "fr" here
```

You can define translation. Read about this [here](/smart-bot/lang-file).

## Debugging

If `debug` is set to `true`, `SmartBot` will provide detailed error messages, which is helpful for troubleshooting and ensuring your bot behaves as expected.

## Best Practices

* **Keep Language Files Updated**: Regularly update your language files to reflect changes in your bot's functionality.
* **Test Thoroughly**: Always test your bot for various scenarios, especially after adding new features or making changes.
* **Handle Errors Gracefully**: Ensure that your bot handles errors smoothly and provides helpful feedback to users.

## Conclusion

Setting up and initializing `SmartBot` is a straightforward process. By carefully configuring your language files and utilizing the robust features of `SmartBot`, you can create an interactive and user-friendly bot experience. Remember to test extensively and update your language files as your bot evolves.


# SmartTasker

## Introduction

`SmartTasker` is a comprehensive class designed for task management within bot applications. It offers a robust framework for handling tasks, tracking user progress, managing rewards, and more. This guide provides an overview of the `SmartTasker` class, explaining its core functionalities and how to effectively integrate it into your bot projects.

{% hint style="success" %}
We have bot demo: [BBDemoTaskBot](https://t.me/BBDemoTaskBot) - free available in the Store.&#x20;
{% endhint %}

### Key Features

* Task Management: Manages a list of tasks and user interactions with these tasks.
* Progress Tracking: Keeps track of user's completed and ongoing tasks.
* Reward System: Manages a balance system for rewarding users upon task completion.
* Dynamic Task Execution: Supports dynamic handling and execution of tasks based on user input and actions.

## Constructor

The constructor initializes the `SmartTasker` with necessary configurations.

#### Syntax:

```javascript
constructor(options);
```

#### Parameters:

* `options`: An object containing initial settings such as task list, balance, and a reference to `SmartBot`.

#### Example:

```javascript
let tasker = new SmartTasker({
  tasks: [...],
  balance: 100,
  smartBot: botInstance
});
```

## Core Methods

### getTasksForWork

Fetches tasks available for the user to work on.

**Usage:**

```javascript
let availableTasks = tasker.getTasksForWork();
```

### skipTask

Skips the current task and moves to the next one.

**Usage:**

```javascript
let hasNext = tasker.skipTask();
```

### defineTask

Defines the current task based on the task ID or task definition.

**Usage:**

```javascript
tasker.defineTask(taskIdOrDefinition);
```

### completeExecution

Marks the current task as completed and processes the reward.

**Usage:**

```javascript
tasker.completeExecution(taskId);
```

### addBalance

Adds a specified amount to the user's balance.

**Usage:**

```javascript
tasker.addBalance(amount);
```

### prepareTaskQuestion

Prepares a question related to a task for user interaction.

**Usage:**

```javascript
tasker.prepareTaskQuestion({ taskID: 'task1', onAnswer: 'handleAnswer' });
```

### acceptAnswer

Processes the user's answer to a task question.

**Usage:**

```javascript
let result = tasker.acceptAnswer(params);
```

###

## Best Practices

* **Consistency in Task Definitions**: Ensure that tasks are defined consistently and include all necessary information.
* **Error Handling**: Utilize the built-in error handling capabilities of `SmartTasker` to manage exceptions and provide feedback to users.
* **Integration with SmartBot**: Leverage the integration with `SmartBot` for a seamless user experience.
* **Task Progress Persistence**: Implement persistence mechanisms to save user progress and task completions.


# Amount Dialog

## Overview

SmartAmountDialog is a tool designed to help process and validate numerical inputs from users, especially when it involves monetary amounts.

This tool is handy for checking conditions such as minimum and maximum amounts, integer-only inputs, and ensuring the amount doesn't exceed the user's current balance.

### Key Features

* **Minimum and Maximum Values**: Set boundaries for the input amount.
* **Integer-Only Values**: Checks if the input number is an integer.
* **Customizable Error Messages**: User-friendly messages for each type of error.

## How It Works

First, you need to create an instance of `SmartAmountDialog` with necessary parameters. Here’s an example of how to do this:

```javascript
let smartAmountDialog = new SmartAmountDialog({
  min: 10,                // Minimum acceptable amount
  max: 100,               // Maximum acceptable amount
  curValue: 50,           // Current amount (e.g., user's balance)
  onlyInteger: true,      // Requires only integer numbers
  skipZero: false,        // Don't skip zero values
  dialogErrors: {         // Error messages
    invalid: "Not a number",
    zero: "Your balance is zero",
    notEnough: "Not enough funds",
    small: "Amount too small",
    big: "Amount too large",
    notInteger: false // accept float on false and integer only on true
  }
});
```

## Usage

To use `SmartAmountDialog` to check an input amount, you call the `accept` method and pass the string value to it. If the method returns `true`, it means the input value passed all checks.

Otherwise, you can retrieve the error message from `errMsg`.

Example:

```javascript
let userInput = "30"; // Imagine this is the value entered by the user
let isValid = smartAmountDialog.accept(userInput);

if (isValid) {
  Bot.sendMessage("This amount is valid: " + smartAmountDialog.amount)
} else {
  Bot.sendMessage("Error: " + smartAmountDialog.errMsg);
}
```

## Using with SmartBot

For example, we already have:

* smartBot object
* command with "acceptAmount" name. It have checked **Wait For Answer** option.

### Template

We can use SmartBot with Command Template:

```javascript
// Template for command "acceptAmount"
    acceptAmount:{
      // any other fieilds here
      /// ...
      // we use "dialogErrors" section for error messages
      dialogErrors: {
        // if user enter not a number
        invalid: "❌ *Invalid amount.*\n \"{_amount}\" - not valid." +
          "\n\nPlease enter valid amount for withdraw request (max: {_curValue}).",

        // if user have zero balance
        zero: "Your balance is zero. \n\nPlease complete any task before.",

        // if user enter amount more than balance
        notEnough: "❌ *Invalid amount.*\n \"{_amount}\" - not enough balance." +
          "\n\nPlease enter valid amount for withdraw request (max: {_curValue}).",

        // if user enter less then min amount
        small: "❌ *Invalid amount.*\n \"{_amount}\" - too small." +
          "\n\nPlease enter valid amount for withdraw request (min: {_min}, max: {_curValue}).",

        // if user enter too big then max amount
        big: "❌ *Invalid amount.*\n \"{_amount}\" - too big." +
          "\n\nPlease enter valid amount for withdraw request (max: {_max}).",

        // if user enter not integer amount
        notInteger: "❌ *Invalid amount.*\n \"{_amount}\" - not integer."
      }
    },
```

**All fields:**&#x20;

| Field      | Description                         |
| ---------- | ----------------------------------- |
| \_amount   | amount for validation               |
| \_min      | minimal value                       |
| \_max      | maximal value                       |
| \_curValue | current value - amount must be less |

### Initialization

```javascript
let smartAmountDialog = new SmartAmountDialog({
  // options like befire:
  min: 10,                // Minimum acceptable amount
  max: 100,               // Maximum acceptable amount
  curValue: 50,           // Current amount (e.g., user's balance)
  onlyInteger: true,      // Requires only integer numbers
  skipZero: false,        // Don't skip zero values
  // we need to pass smartbot now:
  smart_bot: smartBot,
  // and we pass errors from Template:
  dialogErrors: smartBot.curCommand.dialogErrors
});
```

then we can use checking as before


# What it is - Libs?

Libs - it is common functionality. You can use it for any your tasks.

For example Bots.Business have such Libs:

* Random Lib - for random messages from bot
* Referral Lib - for referral tracking
* ResourcesLib - for chat resources with growth and etc
* Lang Lib - for multi language
* etc

### How to install Lib to bot?

1.Go to Libs Tab in the App

![](/files/-LYt3ImwM9mgtQJfH_tO)

2\. Click on Install button

3\. Select your bot

### How to use Lib?

Please see help article for this Lib.

## Github repo

All public official BB libs avaible in <https://github.com/bots-business/store-libs>

&#x20;


# Libs development

You can create own Lib. Now it is possible create lib only with Git [importing](https://help.bots.business/git/import-bot-from-git-repository).

Official Bots.Business repository available [here](https://github.com/bots-business/store-libs)

You can store common code in the library.

{% hint style="success" %}
See libraries in the Library Store. You can copy any free library and modify it.
{% endhint %}

## Basic

For example: code in file libs\myLib.js:

```javascript
function hello(){
  Bot.sendMessage("Hello from lib!")
}

function goodbye(name){
  Bot.sendMessage("Goodbye, " + name)
}

publish({
  sayHello: hello,
  sayGoodbyeTo: goodbye     
})
```

then you can use Lib in any bot's command:

```javascript
Libs.myLib.hello()
Libs.myLib.sayGoodbyeTo("Alice") 
```

## Commands capturing

It is possible to capture command with lib.

For example:

* user type "Hi"
* bot answer "Hello"&#x20;

```javascript
function onHiCommand(){
    Bot.sendMessage("Hello");
}

on('Hi', onHiCommand );
```

Master command "\*" - for capture any text from user with lib

```javascript
function onMasterCommand(){
    /// input your code here
}

on('*', onMasterCommand );
```

{% hint style="info" %}
You can use all BJS functions in the Libs&#x20;
{% endhint %}

## Using HTTP

Lib can perform web requests. For example: get page from eample.com and send its content to user.

```javascript
libPrefix = "myLib"

function load(){
  HTTP.get( {
    url: "http://example.com",
    success: libPrefix + 'onLoading '
    // headers: headers - if you need headers
  } )
}

function onLoading(){
   Bot.sendMessage(content);
}

on(libPrefix + 'onLoading', onLoading );
```

on Bot command:

```javascript
Libs.myLib.load();
```

See [more](https://help.bots.business/scenarios-and-bjs/send-http-request)


# RefferalLib

Use this Lib for referral tracking.

**Demo bot:** <https://telegram.me/DemoReferalTrackingBot>

{% hint style="info" %}
RefferalLib is core Lib now - installation is not needed!
{% endhint %}

## Getting started

Basic function is **track**. Prefer to call it on **/start**:

`RefLib.track(trackOptions);`

params `trackOptions` - it is object with callback functions for:

| Attribute              | **Description**                                                                                                                                                                                                                                                                  |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `onTouchOwnLink()`     | user touch own ref link                                                                                                                                                                                                                                                          |
| `onAlreadyAttracted()` | user already attracted                                                                                                                                                                                                                                                           |
| `onAttracted(byUser)`  | user was attracted by other user byUser - it is common user data (fields: nickname, first\_name and etc)                                                                                                                                                                         |
| `linkPrefix`           | <p>Prefix for link. By default it is "user":<br><https://t.me/botName?start=><strong>user</strong>ID<br><br>You can change linkPrefix in any time but all old links will be broken!<br><br>Please check all your <a href="/pages/-LbHQ_HbTklItxsX1uES">deep link</a> params!</p> |

{% hint style="info" %}
See [@DemoReferalTrackingBot](https://telegram.me/DemoReferalTrackingBot?start=FromLibPage) for details (Available in the Store)
{% endhint %}

### Example

**Command /start**

```javascript
// Command /start

// this function will be executed if user poress own ref link
function onTouchOwnLink(){
   Bot.sendMessage("It is your ref link!")
}

// user can restart bot by ref link again
function onAlreadyAttracted(){
   Bot.sendMessage("You already joined")
}

// it is new user. He start bot via ref link
function onAttracted(byUser){
   Bot.sendMessage("Thank you for joining!" +
                    "Your friend TG id is: " + byUser.telegramid)
   // you can add bonus here...
}

RefLib.track({
   onTouchOwnLink: onTouchOwnLink,
   
   onAlreadyAttracted: onAlreadyAttracted,
   
   onAttracted: onAttracted,
   
   // you can use "", "r" and etc for prefix
   // if you change it - you need to pass same linkPrefix for
   //  RefLib.getLink() also!
   // Prefix "user" is used by default
   // linkPrefix: "user",
   
   // you can pass debug for external debug info
   //debug: true,
   
   // we can use List or TopBoardLib for Top List
   // by default TopBoardLib is used
   // useList: false
   
   // if useList - false (TopBoardLib is used)
   // you can pass max board count
   // it is 10 by default
   // topBoardMaxCount: 15
});
```

## Functions

### Get Referral link for current user

`RefLib.getLink();`&#x20;

will generate link kind **<http://t.me/botname?start=userUSER\\_ID>**

Also you can pass other bot name. For example - it is link for current bot:

`RefLib.getLink(bot.name);`&#x20;

will generate link kind <http://t.me/**botname**?start=userUSER\\_ID>

It is possible to change link prefix:

`RefLib.getLink(bot.name, "r");`&#x20;

will generate link kind <http://t.me/botname?start=**r**USER\\_ID>

### Get attractor for current user

`RefLib.getAttractedBy()`&#x20;

return attractor user data

### Remove ref data for (not worked - known bug)

{% hint style="danger" %}
It is not working now. We will fix it.&#x20;
{% endhint %}

It is test method. You can run it and check ref link again like new user.

`RefLib.clearRef()`

### Get refList

`RefLib.getRefList();`&#x20;

return [list](/bjs/lists) with attracted users.

Or get for Ref List for another user:

`RefLib.getRefList(another_user_id);`

{% hint style="info" %}
This method return users [list](/bjs/lists). You can [paginate](/bjs/lists#paginating) it, [sort](/bjs/lists#ordering), [recount](/bjs/lists#recount-list) it and etc.
{% endhint %}

then code  for `/reflist` can be:

```javascript
let refList = RefLib.getRefList();

if (!refList.exist) {
  Bot.sendMessage("No any affiliated users")
  return
}

let users_rows = ""

// only 100 first users here
// for other users you need use pagination:
// https://help.bots.business/bjs/lists#paginating
let users = refList.getUsers();

for (var ind in users) {
  users_rows = users_rows + "\n👤 " + CommonLib.getLinkFor( users[ind] )
}

let msg =
  "*Total users:* " +
  RefLib.getRefCount() +
  "\n _the first user was tracked:_ \n" +
  "   _" +
  refList.created_at +
  "_" +
  "\n----" +
  users_rows
  
Bot.sendMessage(msg);
```

### Get refferals count

`RefLib.getRefCount()`

or for another user:

`RefLib.getRefCount(another_user_id)`

### Get Top Refferal List

`RefLib.getTopList()`

```javascript
// It is just List
// you can order, paginate it!
// https://help.bots.business/bjs/lists#getting-data 
let list = RefLib.getTopList();

// It is only for List
//   by default TopBoardLib is used
//   see useList param in track
// list.order_by = "integer_value";

// olso it is possible get newest members:
// list.order_ascending = false;

var items = list.get();
//Bot.inspect(items);

var msg = 'Top list: ';
var prop;
for(var ind in items){
  prop = items[ind]
  msg = msg + "\n" +
    String( parseInt(ind) + 1 ) + ". " + 
    CommonLib.getLinkFor(prop.user) + ": 👨" +
    String(prop.value)
}

Bot.sendMessage(msg);
```

## How to

**Q: How to give bonus to user for attracted friend?**

**Answer:**

We can use [ResourcesLib](https://help.bots.business/libs/resourceslib) for this.

on `/start`

```javascript
function onAttracted(refUser){
  // access to Bonus Res of refUser
  let refUserBonus = ResLib.anotherUserRes("money", refUser.telegramid);
  refUserBonus.add(100);  // add 100 bonus for friend
}

RefLib.track({
   onAttracted: onAttracted
});
```

**Q: how to give to referrer 5% of referral user deposit?**

**Answer:**

1. You need setup [track](https://help.bots.business/libs/refferallib#getting-started) in first
2. Seems you need use [ResLib](https://help.bots.business/libs/resourceslib)
3. On user set balance:

```javascript
let res = ResLib.userRes("money");
let referrer = RefLib.getAttractedBy();

// if current user was attracted by referrer
if(referrer){
   let referrerRes = ResLib.anotherUserRes(
       "money", referrer.telegramid);
   
   let amount = res.value * 0.05; // it is 5%
   referrerRes.takeFromAnother(res, amount);
}
```

{% hint style="info" %}
In this example we use userRes. Also it is possible use chatRes. See [ResourcesLib](https://help.bots.business/libs/resourceslib) for details
{% endhint %}


# ResourcesLib

With lib we can manage any resources in bot.

{% hint style="warning" %}
It is bad practice to use Res for counting. Use simple Integer or Float types for it and setProp!

\
ResourcesLib is good for using it with [growth](#growth-for-resource). If you don't have growth it is possible you don't need use this lib.
{% endhint %}

## Resource can be

* balance (in USD, BTC or any other)
* any game resources: gold, woods, stone, etc
* etc, any float values

## User's resource

```javascript
let res = Libs.ResourcesLib.userRes("money");
Bot.sendMessage("Cur your money: " + res.value());
```

{% hint style="danger" %}
Res name is case sensitive. The resources “money”, “Money” and “MONEY” do not match. These are 3 separate resources.
{% endhint %}

{% hint style="info" %}
One user can have same chats with bot.&#x20;

**For example:** private and group chat.&#x20;

But anywhere he have **simular** resources
{% endhint %}

## Chat's resource

```javascript
let res = Libs.ResourcesLib.chatRes("money");
Bot.sendMessage("Cur your money: " + res.value());
```

{% hint style="info" %}
One user can have same chats with bot.&#x20;

**For example**: private and group chat.

But he have **diffent** resources for each chats.
{% endhint %}

## Methots for user's and chat resources

All methods can be for user's or chat's resources.

```javascript
// get res
let res = Libs.ResourcesLib.userRes("money");
```

`res.name` - current res name. For example:&#x20;

```javascript
Libs.ResourcesLib.chatRes("BTC").name // is "BTC"
```

## Basic functions

### Current res amount

`res.value()`&#x20;

### Set amount for this res&#x20;

`res.set(amount)`&#x20;

for example: `Libs.ResourcesLib.userRes("wood").set(10);`

### Add amount for this res

`res.add(amount)`&#x20;

### Res have such amount?

`res.have(amount)`- if res value equal amount or more return true

### Take away amount from resource

`res.remove(amount)` -  if have it res.removeAnyway(amount) - take away amount anyway.

## Access to another resources

### Access to another user's resources

```javascript
// telegramid - it is telegram id for another user
let res = Libs.ResourcesLib.anotherUserRes("money", telegramid);
Bot.sendMessage("Cur your money: " + res.value());
```

### Access to another chat's resources

```javascript
// another chat's resources
// chatid - it is telegram id for another chat
let res = Libs.ResourcesLib.anotherChatRes("money", chatid);
Bot.sendMessage("Cur your money: " + res.value());
```

## Resource transfering&#x20;

```javascript
let res = Libs.ResourcesLib.userRes("gold");
// telegramid - it is telegram id for another user
let anotherRes = Libs.ResourcesLib.anotherUserRes("gold", telegramid);
```

### If have resource...

```javascript
res.takeFromAnother(anotherRes, amount);
res.transferTo(anotherRes, amount)
```

### ...or anyway, even resource is not enough

```javascript
res.takeFromAnotherAnyway(anotherRes, amount)
res.transferToAnyway(anotherRes, amount)
```

### Can exchange different resources

For example "gold" for "wood":

`res.exchangeTo(anotherRes, { remove_amount: 10, add_amount:23 } )`

## Growth for resource.

Resource can have growth.

{% hint style="info" %}
For example simple growth:

**add 5 every 10 secs to res**
{% endhint %}

```javascript
let health = Libs.ResourcesLib.userRes("health");
health.set(1);
health.growth.add({value: 5, interval:10 });
```

Interval - it is value in seconds. Value is added every interval

### Add 5 every hour with max value 100.

```javascript
//Max value: 100
let secs_in_hour = 1 * 60 * 60;
health.growth.add({
  value: 5,
  interval: secs_in_hour,
  max: 100
});
```

### Value can be negative. Remove 5 every 30 hours.&#x20;

```javascript
//Min value: -20
let secs_in_30hours = 1 * 60 * 60 * 30;
health.growth.add({
  value: -5,  // just add negative value
  interval: secs_in_30hours,
  min: -20
});
```

### Can limit max iteration count

```javascript
health.growth.add(
   {value: 5,
   interval: secs_in_30hours,
   max_iterations_count: 3
});
```

### Can growh by percent.&#x20;

For example add 15% every month for 100 USD

```javascript
let usd = Libs.ResourcesLib.userRes("usd");
usd.set(100);
let secs_in_month = 60 * 60 * 24 * 31;
usd.growth.addPercent({
  value: 15,
  interval: secs_in_month
});
```

### Can grow by compound interest.

For example add 0.8% every day for 0.5 BTC with reinvest

```javascript
let btc = Libs.ResourcesLib.userRes("BTC");
btc.set(0.5);
let secs_in_day = 1 * 60 * 60 * 24;
usd.growth.addCompoundInterest({
  value: 0.8,
  interval: secs_in_day
});
```

{% hint style="info" %}
You can get initial res value by: `res.baseValue()`
{% endhint %}

### Reset growth

Growth will be removed

```javascript
let usd = Libs.ResourcesLib.userRes("usd");
usd.resetGrowth();

```

### Other methods for res.growth:&#x20;

`res.growth.info()` - get info for current growth

`res.growth.title()` - get title. For example "add 5 once at 15 secs"&#x20;

`res.growth.isEnabled()` - return true if is enabled&#x20;

`res.growth.stop()` - stop growth

`res.growth.resume()` - resume growth after stop

`res.growth.remove()` - remove growth

`res.growth.progress()` - current progress for next iteration&#x20;

`res.growth.willCompletedAfter()` - will completed iteration after this time in seconds

###

### How to add growth to another resources?

For example we have:

* bank deposit 100$ with yearly growth 10%
* and simple wallet - 500$

Every year we add bank growth to wallet.

#### **Init:** on `/start` command (or any other command)

```javascript
let wallet = Libs.ResourcesLib.userRes("wallet");
wallet.set(500);

let bankDeposit = Libs.ResourcesLib.userRes("deposit");
bankDeposit.set(100);
let secs_in_year = 1 * 60 * 60 * 24 * 365;

bankDeposit.growth.addPercent({
  value: 10,
  interval: secs_in_year
});
```

#### **On** `/wallet` command or etc

{% hint style="info" %}
We can run this command every 1 year. It is possible for example, with [Auto Retry](https://help.bots.business/commands/auto-retry)

Or user can run it manually in anytime.
{% endhint %}

```javascript
let wallet = Libs.ResourcesLib.userRes("wallet");
let bankDeposit = Libs.ResourcesLib.userRes("deposit");

// it is initial res value
let baseValue = bankDeposit.baseValue();

// total income by percent
let delta = bankDeposit.value() - baseValue;

// add all income to wallet
wallet.add(delta);
// and remove it from bank deposit
bankDeposit.set(baseValue);
```

## How to

### **Q: How to give to referrer 5% of referral user deposit?**

Please see <https://help.bots.business/libs/refferallib#how-to>

### **Q: How to give a bonus to all users every day?**

For example add 10 to user's balance every day

Command `/start`

```javascript
let balance = Libs.ResourcesLib.userRes("balance");
balance.set(0);

Bot.run( {
    command: "/addBonus",
    run_after: 1*60*60*24,  // add bonus after 1 day
} )
```

&#x20;Command `/addBonus`

```javascript
if(request){
  // user can not run this command manually
  Bot.sendMessage("Restricted!")
  return
}

let balance = Libs.ResourcesLib.userRes("balance");
balance.add(10);

// and repeat this command again after 1 day 
Bot.run( {
    command: "/addBonus",
    run_after: 1*60*60*24,  // after one day
} )

Bot.sendMessage("Bonus for you: 10")
```

{% hint style="warning" %}
Command /addBonus will be executed for each user. It spend 1 iteration every day for each user.

For example, for 100 user - it will be 100 iterations per day.
{% endhint %}

###

### **Q: How to make time limit bonus?**

{% hint style="success" %}
Use [Cooldown Lib](/libs/cooldown-lib)! It is more simple!
{% endhint %}

For example, user can get bonus once at 5 hours.

&#x20;Command `/bonus`

```javascript
let bonusCooldown = Libs.ResourcesLib.userRes("bonusCooldown");

// cooldown in seconds
let totalCooldown = 60*60*5; // 60*60*5 seconds = 5 hours

function resetCooldown(){
   bonusCooldown.set(totalCooldown); 
}

function setupCooldown(){
  if(bonusCooldown.growth.isEnabled()){
     // already setupped
     return
  }
  
  bonusCooldown.growth.add({
    value: -1,  // just add negative value
    interval: 1, // -1 once at 1 sec
    min: 0
  });
}

setupCooldown();

if(bonusCooldown.value() > 0){
   Bot.sendMessage("Please wait: " + bonusCooldown.value() + " secs" );
   return
}
 
// can give bonus now
resetCooldown(); // need to reset cooldown

Bot.sendMessage("You have bonus now");
// your other code here
//..

```


# Random

Send random message to user with this lib and get random values!

## Example BJS code:

`Libs.Random.sendMessage(["hello", "Hi", "Good day!", "Welcome!"]);`

## Get random integer value beetwen 0 and 10:

`Libs.Random.randomInt(0, 10);`

## Get random float value beetwen 200 and 400

`Libs.Random.randomFloat(200, 400);`


# MembershipChecker (MCL)

This library is used to verify user membership in other channels and chats. It is also know as MCLib (MCL)

{% hint style="success" %}
We have demo bots for MCLib in the Store - [BBJoinBot](https://t.me/BBJoinBot) and [BBChannelPromotionBot](https://t.me/BBChannelPromotionBot)
{% endhint %}

{% hint style="warning" %}
It is recommended to use this library, since it allows you to make the bot work faster.
{% endhint %}

{% hint style="info" %}
Verification methods run in the background so the user does not need to wait for a response from the bot.
{% endhint %}

## Initial setup

Install Library and create `/setup` command:&#x20;

```javascript
Libs.MembershipChecker.setup()
```

Then go to App > Bot > Admin Panels and fill options:

<figure><img src="/files/zVpz5tTqngMmC789kY5n" alt=""><figcaption></figcaption></figure>

{% hint style="warning" %}
Please note:&#x20;

* **Small** checking **delay** is not good for iterations
* **One chat** (or one channel) require **1 iteration per check**
* you can turn on "debug info" checkbox for bug searching
  {% endhint %}

## Setup

### Callbacks

You need to define commands in the admin panel. You can define only those commands that you need.

| Callback command   | Description                                 |
| ------------------ | ------------------------------------------- |
| `onNeedJoining`    | user still need to join to **any** resource |
| `onNeedAllJoining` | user still need to join to **all** resource |
| `onJoining`        | user just joined to **any** resource        |
| `onAllJoining`     | user just joined to **all** resources       |
| `onStillJoined`    | user is still joined to **all** resources   |
| `onError`          | error callback                              |

[**Before all**](/bjs/always-running-commands) **command**

in @ command:

```javascript
// for automatic checking
// with checking delay from admin panel

if(chat?.chat_type == "private"){
    // we check joining only in private chat
    Libs.MembershipChecker.handle();
}
```

{% hint style="warning" %}
This method can have much more iterations usage.&#x20;

You can increase checking delay time for hour and etc for decreasing iterations usage.

Also you can use it only on `/start` - but user can leave your channel after joining and bot starting. With @ command it is permanent checking.
{% endhint %}

{% hint style="info" %}
We use  (`chat?.chat_type == "private")` because in group chat (usually) joining checking is not needed.&#x20;
{% endhint %}

### Command `/onNeedJoining`

```javascript
Bot.sendMessage(
  "You still need to join: " + options.chat_id
)

// you can access for passed data:
// Bot.inspect(options.bb_option)
```

{% hint style="success" %}
This callback will be executed if the user has not yet joined or has left after `handle()` or `check()` methods
{% endhint %}

{% hint style="info" %}
This callback will be executed **per each channel or chat**. For example, if you have 5 not joined chats you will have 5 callbacks
{% endhint %}

### Command `/onJoining`:

```javascript
if(!options){ return } // protect from manual run
Bot.sendMessage("Thank you for joining to" + options.chat_id);

// you can access for passed data:
// Bot.inspect(options.bb_option)
```

{% hint style="success" %}
This callback will be executed if the user just joined after after `handle()` or `check()` methods
{% endhint %}

{% hint style="info" %}
This callback will be executed if the user **just joined to any channel**
{% endhint %}

### Command `/onAllJoining`:

```javascript
if(!options){ return } // protect from manual run
Bot.sendMessage("Thank you for joining!");

// you can access for passed data:
// Bot.inspect(options.bb_option)
```

{% hint style="success" %}
This callback will be executed if the user just joined after after `handle()` or `check()` methods
{% endhint %}

{% hint style="info" %}
This callback will be executed **once** if the user **has joined all channels**
{% endhint %}

### Command  /onStillJoined

```javascript
Bot.sendMessage(
  "You still have membership in our groups. Thank!"
)
```

{% hint style="success" %}
This callback will be executed if the user **still joined to all** channels and chats after  `check()` method only.
{% endhint %}

## Limited bot access

If membership is required to use the bot you can use [before all](https://help.bots.business/scenarios-and-bjs/always-running-commands#beforeall-and-afterall-commands) command: `@`

```javascript
// for all chats and channels:
let isMember = Libs.MembershipChecker.isMember();

// for one chat / channel:
// isMember = Libs.MembershipChecker.isMember("@chatName")

// we need this commands because user always need
// to /start bot and make "/check" command
const skipCommands = [
   "/start",
   "Check", "/check",
    //  "/setup"   // it is also can be
];

const canRunBot = isMember || skipCommands.includes(message);

if(!canRunBot){
  let channels = Libs.MembershipChecker.getChats();
  Bot.sendMessage("Please join to our channels " + channels)
  return // return from bot execution
}

```

## Check button

You can also perform manual check if you need something like "check" button.&#x20;

<figure><img src="/files/WsTtKoO78j9KFUULguXO" alt=""><figcaption></figcaption></figure>

Example for `/check` command:

```javascript
// for all chats and channels:
// this method perform checking without delay
// but not more often than once every 2 seconds
Libs.MembershipChecker.check()

// also you can pass any data for callbacks:
// Libs.MembershipChecker.check({ any: "data", here: "for callbacks"  })
```

{% hint style="info" %}
It is good to use [Cooldown Lib](/libs/cooldown-lib) here

User can press button many times. So we can restrict this and save iterations
{% endhint %}

##

## All methods

| Method                | Description                                                                                                                                                                                                                                                                                  | Background |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| `setup()`             | Install Admin Panel for Lib                                                                                                                                                                                                                                                                  |            |
| `check(options)`      | <p>Force check memberships. </p><p></p><p>You can pass any data in options for callbacks (<code>onJoining</code>, <code>onNeedJoining</code>, <code>onNeedAllJoining</code>, <code>onStillJoined</code>)</p>                                                                                 | **+**      |
| `handle(options)`     | <p>Soft check memberships with delay (you can setup delay in Admin Panel). <br><br>Use this method in <a href="/pages/-LsWOlRvn5_RXefEJC9L#beforeall-and-afterall-commands">before all</a> @ command<br><br>You can pass any data in options for callbacks (onJoining and onNeedJoining)</p> | **+**      |
| `isMember(chat_id)`   | <p>Returns true if the user has joined all resources. chat\_id - can be null (it will be all chats)<br><br>Before you need to execute handle() or check()</p>                                                                                                                                |            |
| `getChats()`          | Returns all resources (group chats, channels) specified in the Admin Panel                                                                                                                                                                                                                   |            |
| `getNotJoinedChats()` | Returns all resources (group chats, channels) specified in the panel that the user has not yet joined                                                                                                                                                                                        |            |

{% hint style="info" %}
All background methods require additional iterations.
{% endhint %}


# Cooldown Lib

Use this Lib to make cooldown.&#x20;

Cooldown have name and can be for user or for chat.

### Example

Command `/bonus`

```javascript
function onEnding(time){
  // can give bonus now
  Bot.sendMessage("You have bonus now");
  // your other code here
  //..

  return true; // if false - cooldown is not restarted
}

function onStarting(){
  // cooldown just started
  Bot.sendMessage("You will have bonus later");
}

function onWaiting(waitTime){
  // we have active cooldown
  Bot.sendMessage("Please wait: " + waitTime + " secs" );
}

Libs.CooldownLib.user.watch({
  // you need name for cooldown
  name: "GemBonusCooldown",
  time: 120, // cooldown time, 120 secs - 2 minute
  onStarting: onStarting,
  onEnding: onEnding,
  onWaiting: onWaiting
})
```

**or cool down for chat:**

```javascript
// or cooldown for chat:
Libs.CooldownLib.chat.watch({
  // you need name for cooldown
  name: "GemBonusCooldown",
  time: 120, // cooldown time, 120 secs - 2 minute
  onStarting: onStarting,
  onEnding: onEnding,
  onWaiting: onWaiting
})


// or global bot cooldown
// it can be used with Auto Retry (then chat or user are null)
/*
Libs.CooldownLib.watch({
  // you need name for cooldown
  name: "GemBonusCooldown",
  time: 120, // cooldown time, 120 secs - 2 minute
  onStarting: onStarting,
  onEnding: onEnding,
  onWaiting: onWaiting
})
*/
```

**get cool down:**

```javascript
// get current cooldown res for chat
let cooldown = Libs.CooldownLib.chat.getCooldown("GemBonusCooldown");

// for user:
// let cooldown = Libs.CooldownLib.user.getCooldown("GemBonusCooldown");

// global
// let cooldown = Libs.CooldownLib.getCooldown("GemBonusCooldown");

cooldown.value(); // current cooldown in second
cooldown.set(60 + cooldown.value()) // add 60 sec to cooldown
```

Command `/bust`

```javascript
// get current cooldown Res - see ResourcesLib
let cooldown = Libs.CooldownLib.chat.getCooldown("GemBonusCooldown");

// for user:
// let cooldown = Libs.CooldownLib.user.getCooldown("GemBonusCooldown");

// global
// let cooldown = Libs.CooldownLib.getCooldown("GemBonusCooldown");

var curValue = cooldown.value(); // current cooldown in second
cooldown.set(curValue - 40) // reduce 40 sec from cooldown
```


# CurrencyConverter

Conversion is as easy as a few lines of code!

{% hint style="warning" %}
This Lib is deprecated. Use [CurrencyQuote](/libs/currencyquote) Lib
{% endhint %}

Currency values are refreshed every 60 minutes.

## FREE

* Maximum of 100 requests/hr
* Shared with all users who are acccessing it for free.
* Downtime when there's a need to restart the server for bug fixes and enhancements

## PAID

Register in <https://www.currencyconverterapi.com/pricing>

Get your API key and run in `/setup`

```javascript
Libs.CurrencyConverter.setupApiKey(API_KEY);
```

## Example bot @DemoCurrencyConverterBot

## Example code

In any command:

```javascript
let amount = 1;
let onSucces = '/onconvert';
let conversation = 'USD_EUR' // others: USD_BTC, BTC_USD, CNY_BTC and etc...
Libs.CurrencyConverter.convert(conversation, amount, onSucces);
```

### In command '/onconvert':

```javascript
// result stored in params
Bot.sendMessage(params);
```


# Lang

Lib for multi language support

## introduction

It is important to understand:

* Any bot can be translated
* The bot consists of commands in which there are no untranslated places.
* All commands are multilingual
* There are no commands like `/menuEn`,  `/menuFr, /menuRu`. There is only one `/menu` command
* All multilingual texts must be placed in each language files (command), for example, in lng-en, lng-ru. This will make them easier to translate.
* everything can be translated: any text, answer, keyboard, inline keyboard, alert...

{% hint style="danger" %}
This is especially important for large bots
{% endhint %}

## Getting started

First - need to setup languages. For example with **/setup** command:

```javascript
const enLang = {
    user: { whatIsYourName: "What is your name?" },
    hello: "Hello!",
    onlyOnEnglish: "Only on english"
    keyboards: {
        mainMenu: { buttons: "Bonus, Friends", text: "menu" }
        bonusMenu: { buttons: "Get bonus, Back", text: "Get your bonus now" }
    }
}

const ruLang = {
    user: { whatIsYourName: "Как тебя зовут?" },
    hello: "Привет!",
    // not translated yet:
    // onlyOnEnglish: "Only on english"
    keyboards: {
        mainMenu: { buttons: "Бонус, Друзья", text: "меню"}
        bonusMenu: { buttons: "Получить бонус, Назад", text: "получи бонус"}
    }
}

// first language is default language
Libs.Lang.setup("en", enLang);  // english is default now
Libs.Lang.setup("ru", ruLang);
```

Now default language is "english".

You can use lib now (for example, in command `/test`):

```javascript
const lang = Libs.Lang;
// send messages on default language
Bot.sendMessage(lang.t("hello"))   // Hello!
Bot.sendMessage(lang.t("user.whatIsYourName"))  // What is your name?

Bot.sendMessage(lang.t("onlyOnEnglish")) // "Only on english"
// Default language text always is used
//  for non translated keys yet


// send keyboard for Main menu:
Bot.sendKeyboard(
  lang.t("keyboards.mainMenu.buttons"),
  lang.t("keyboards.mainMenu.text")
)

// or send Bonus menu:
Bot.sendKeyboard(
  lang.t("keyboards.bonusMenu.buttons"),
  lang.t("keyboards.bonusMenu.text")
)
```

## How to use

### Change user lang

`Libs.Lang.user.setLang("ru")`

{% hint style="info" %}
`You can get user language code. For example in /start:`

```javascript
// in /start command
let lang_code = request.from.language_code;
Libs.Lang.user.setLang(lang_code)
```

{% endhint %}

### Get cur lang

`let lang = Libs.Lang.user.getLang()`

### Change default lang

```javascript
Libs.Lang.default.setLang("en")
let default = Libs.Lang.default.getCurLang()
```

{% hint style="info" %}
Tips. Also you can use multi lang command. This **is not recommended** but sometimes a good solution
{% endhint %}

**In BJS for command /hello:**

`Bot.runCommand("/hello_" + Libs.Lang.user.getLang())`

{% hint style="success" %}
Also you can use&#x20;

`Libs.Lang.t("translation-key", "ru")`&#x20;

for non user actions: in webhooks and etc
{% endhint %}

### Get translation by language code

Sometimes we do not have user object. For example, on income [webhooks](/libs/webhooks-lib) or with Bot.runAll command and etc. Therefore, we cannot determine the current language.

The following code might be helpful in such cases.

```javascript
// command /test
// you can pass language code in params
let lng = params;
// or in options with Bot.run(command: "/test", options: {lngCode: "fr"} )
let lng = options.lngCode

// So now:
// lng = "fr"

Bot.sendMessage(
    Libs.Lang.t("hello", lng)
)   // Привет!
```

### Get all language json

```javascript
// get all json for default language:
Bot.sendMessage(Libs.Lang.get())

// get all json for "ru":
Bot.sendMessage(Libs.Lang.get("ru"))
```

### Using aliases

You can set aliases for language.

For `/setup`

```javascript
const enLang = {
    aliases: {
       // Command /start have aliases:
       //       home, dashboard and /main:
       "home, dashboard, /main": "/start",
       
       // command /otherCommand have aliases:
       //       alias1, alias2
       "alias1,alias2": "/otherCommand"
    }
    user: { whatIsYourName: "What is your name?" },
}

Libs.Lang.setup("en", enLang);
```

For [Master command](https://help.bots.business/scenarios-and-bjs/always-running-commands#master-command) \* :

```javascript
// find multilanguage aliases
let cmd = Libs.Lang.getCommandByAlias(message);
if(cmd){ Bot.run({ command: cmd }) }

// also it is possible define language
// let cmd = Libs.Lang.getCommandByAlias(message, "ru");
// if(cmd){ Bot.run({ command: cmd }) }
```

&#x20;

## Good practices

### **Use different language files** (command) for each language.

For example "lng-en.js", "lng-fr.js" and etc. So it's easier to translate.&#x20;

In `/setup` you can make something like this:

```javascript
let languages = ["en", "es", "cn", "ru"];
let cmdName;

for(let i in languages){
    cmdName = "lng-" + languages[i].code;
    Bot.run({ command: cmdName })
}

Bot.sendMessage("Multi Languages - installed");
```

### Make a simple command based structure

```javascript
const enLang = {
    command1: {
      text: "your text",
      // keys
      ...
      }
      ...
    }
    command2: {
      text: "your text"
      // keys,
      ...
    }
    // bot menus
    menus: {
      mainMenu: {
        keyboard: 
        text: 
      },
      helpMenu: {
        keyboad:
        text: 
      }
    },
    // common links
    links: {
      homePage: "<a href='example.com'>Home page</a>",
    },
    alert: {
      error: "sorry, we have error"
    }
    ...
}

Libs.Lang.setup("en", enLang);
```

### Make translation for text and keyboard:

```javascript
const enLang = {
    command1: {
       text: "Please confirm",
       keyboard: "Yes, Cancel",
       
       // you can also attach Inline keyboard:
       inlineKeyboard: {
         buttons: [ 
           {title: "google", url: "http://google.com" },
           {title: "other command", command: "/othercommand"}
          ],
          text: "Please make a choice."
        }
    }
    //...
}

Libs.Lang.setup("en", enLang);
```

So in `/command1` you can make:

```javascript
Bot.sendKeyboard(
   Libs.Lang.t("command1.keyboard"),
   Libs.Lang.t("command1.text"),
)

// send inline keyboard:
Bot.sendInlineKeyboard(
   Libs.Lang.t("command1.inlineKeyboard.buttons"),
   Libs.Lang.t("command1.inlineKeyboard.text"),
)
```

### Use aliases translations

See [this](https://help.bots.business/libs/lang#using-aliases)


# TopBoardLib

`TopBoardLib` is a lib designed for managing a leader board in a chatbot. It provides functionality for adding, updating, retrieving, and resetting user scores, as well as managing multiple leader boards.

## Methods

### addScore(params)

Adds or updates a user's score on the leader board.

**Parameters:**

`params`: An object containing:

* `value` (Number): The score value to be added.
* `boardName` (String, optional): The name of the leader board, default is "default".
* `maxCount` (Number, optional): The maximum number of entries on the board, default is 10, max is 25
* `fields` (Object, optional): Additional fields for the user's entry.

{% hint style="success" %}
You can use "fields" for extra any values. This fields can be used later by you.
{% endhint %}

### getBoard(boardName)

Retrieves a leader board by its name.

**Parameters:**

* `boardName` (String, optional): The name of the leader board, default is "default".

**Returns:**

* An array of entries on the leader board.
* each record it is:&#x20;

```javascript
{
        // user data:
        id: user.id,
        tgId: user.telegramid,
        first_name: user.first_name,
        last_name: user.last_name,
        username: user.username,
        language_code: user.language_code,
        // current value
        value: curValue
        // your passed fields:
        fields: { }
 }
```

### resetBoard(boardName)

Resets the leader board, removing all entries.

**Parameters:**

* `boardName` (String, optional): The name of the leader board, default is "default".

###

## Usage Examples

#### in /gameOver command:

```javascript
// we add +5 to Score
let userScore = User.getProperty("score") || 0;
userScore = userScore + 5;

// Adding points to a user
TopBoardLib.addScore({
   value: 5
   // boardName: "Game" // you can pass boar name
});

```

#### in /top command:

```javascript
// Retrieving the leaderboard
let leaderboard = TopBoardLib.getBoard();

let leaderboardText = "The leaderboard is currently empty.";

// Check if the leaderboard is not empty
if (leaderboard.length > 0) {
  // Create a string to represent the leaderboard
  leaderboardText = "🏆 Leaderboard 🏆\n\n";
  leaderboard.forEach((entry, index) => {
    leaderboardText += `${index + 1}. ${entry.tgId}: ${entry.value} points\n`;
  });
}

// Send the leaderboard
Api.sendMessage({ text: leaderboardText });
```

{% hint style="info" %}
You also can pass another user data to TopBoardLib.addScore method
{% endhint %}

```javascript
// another user:
let another_user = { id: ID, telegramid: tgId, first_name: "Smith" }
another_user.value = 10;

// update leaders board
// another user score will be +10:
TopBoardLib.addScore(another_user);
```

## Other methods

`getUserPropName(boardName)` - this method return prop name for storing user's score. You can use it to prevent duplicate information. For example, if you have a user balance, then you can store it with this property name


# QiwiPayments

Track payment with Qiwi.com

## Getting started

{% hint style="warning" %}
Need Api token from <https://qiwi.com/api>
{% endhint %}

### Set Api Token to lib:

`Libs.QiwiPayment.setQiwiApiToken(API_KEY);`

### Get payment link

```javascript
let link = Libs.QiwiPayment.getPaymentLink({
    account: "+7XXXXXXXXXX", // Qiwi wallet
    amount: 250, // amount in RUB
    comment: "u" + String(user.id) // track transaction with label for user or order 
});
```

User can make payment via this link.

### Bot need check payments

```javascript
Libs.QiwiPayment.acceptPayment({
      account: "+7XXXXXXXXXX", // Qiwi wallet
      onSuccess: "/onacceptpayment",
      onNoPaymentYet: "/onnopaymentyet",
      comment: "u" + user.id // track transaction with label for user or order
})
```

If payment recived command `/onacceptpayment` executed.

Params contain amount in RUB:

`let amount = parseFloat(params);`


# CoinPayments (CP)

This Lib make integration with [https://www.coinpayments.net](https://www.coinpayments.net/index.php?ref=5418303a5fc165090ee8a9177a3982de) in easy way.

## Initial setup

Need to setup public and private key:

1. [Register](https://www.coinpayments.net/index.php?ref=5418303a5fc165090ee8a9177a3982de)
2. Go to this [page](https://www.coinpayments.net/acct-api-keys) and generate new key.

![](/files/-LeebKAPe0qT_EzrJLXm)

Press on button "Edit Permissions" and add API Key Permissions:

![Check all options what you need](/files/-Leebe8uO7kxfCmAhQTQ)

Then on bot `/setup` command:

```javascript
// Get your keys in https://www.coinpayments.net/index.php?cmd=acct_api_keys
Libs.CoinPayments.setPrivateKey("YOUR KEY");
Libs.CoinPayments.setPublicKey('YOUR KEY');

// for Receiving Payments
// Get your BB Api Key from Bots.Business App in Profile
Libs.CoinPayments.setBBApiKey('YOUR API KEY');
```

## Call API methods

All CoinPayments API method available [here](https://www.coinpayments.net/apidoc-intro).

For example for method [Get Basic Account Information](https://www.coinpayments.net/apidoc-get-basic-info) we need 2 commands: `/info` and `/onInfo`

`/info` command:

```javascript
Libs.CoinPayments.apiCall({
  fields: { cmd: "get_basic_info"},
  onSuccess: '/onInfo'
});
```

{% hint style="info" %}
In fields you can pass all fields from CoinPayments api. Just read [help](https://www.coinpayments.net/apidoc-intro).&#x20;
{% endhint %}

`/onInfo` command:

```javascript
Bot.sendMessage(inspect(options));
Bot.sendMessage("CoinPayments owner email:" + options.body.result.email);
```

## Combine libs!

CoinPayments API do not have some methods. For example get balance by address, validate address, get transactions for address and etc.

Use Block.io [Lib](https://help.bots.business/libs/blockio) with CP Lib together!

Block.io is free if you do not use wallets there.

## Receiving Payments

{% hint style="success" %}
See [demo bot](https://telegram.me/BBDemoStoreBot). Available in the Store.
{% endhint %}

It is possible to receive payment for a temporary or permanent wallet.

**Temporary wallet benefits:**

* Fixed amount
* Can bind the payment to the ordered product
* Status and checkout page
* QR code for payment
* one address for one payment

**Permanent wallet benefits:**

* Any amount
* One address for several payments
* User can transfer funds at any time

### Setup: set IPN Secret

{% hint style="warning" %}
The first step is to go to the [My Settings](https://www.coinpayments.net/index.php?cmd=acct_settings) page > **Merchant Settings**  and set a IPN Secret.

Your IPN Secret is a string of **your choosing**. Recommended to be a random string of letters, numbers, and special characters.

CoinPayments **will not send** any IPNs unless you have an IPN Secret set.&#x20;

See [more](https://www.coinpayments.net/merchant-tools-ipn)
{% endhint %}

**Once more!** You need input **any text (random text)** as IPN secret in Merchant Settings page

## Temporary wallet

We use command "create\_transaction" with IPN.

Please see <https://www.coinpayments.net/apidoc-create-transaction> for details.

Yes, you can write it via `Libs.CoinPayments.apiCall`method too. But there is an easier way.

####

### Command `/pay`

```javascript
let amount = 0.0001; // amount in BTC

options = {
  fields: {
     amount: amount,   // amount in BTC
     currency: "BTC",  // currency1 = currency2 = BTC
     // currency1: "BTC",   // The original currency of the transaction
     // currency2: "LTC"  //The currency the buyer will be sending
     // buyer_email: "user@example.com",
     // you can use another fields also
     // except custom and ipn_url (it used by Lib)
     // See https://www.coinpayments.net/apidoc-create-transaction
  },
  // generated wallet, QR code, payment page
  // will be available in this command
  onSuccess: '/onCreatePayment',
  
  // on successful payment this command
  // will be executed
  onPaymentCompleted: "/onPaymentCompleted",
  
  // it is not necessary
  // onIPN: "/onIPN"
  
  // if you want customize error messages
  // onError: "/onError"
}

Libs.CoinPayments.createTransaction(options);
```

{% hint style="success" %}

#### Automatically with Library:

#### CoinPayments: [IPN Retries / Duplicate IPNs](https://www.coinpayments.net/merchant-tools-ipn)

{% endhint %}

{% hint style="info" %}
It is preferable to use method  **`onPaymentCompleted`** and not method **`onIPN`**.&#x20;

Since the method **`onPaymentCompleted`** completely covers the IPN and solves the problem with [IPN Retries / Duplicate IPNs](https://www.coinpayments.net/merchant-tools-ipn)
{% endhint %}

### Command `/onCreatePayment`

```javascript
// You can inspect all options:
// Bot.sendMessage(inspect(options));

let result = options.result;

let msg = "*Need pay:*\n `" + result.amount + "`" + 
 "\n\n*to address:*\n" +
 "`" + result.address + "`" +
 "\n\n [Checkout](" + result.checkout_url +
    ") | [Status](" + result.status_url + 
 ")" // you can uncomment this for manual status checking
 // + "\n\nCheck status manually: /check" + options.payment_index;

Bot.sendMessage(msg);
Api.sendPhoto({ photo: result.qrcode_url }); 

```

### Command `/onPaymentCompleted`

This command will be executed on successful payment

{% hint style="info" %}
Need install ResourcesLib
{% endhint %}

```javascript
// you can inspect all options
// Bot.sendMessage(inspect(options));

if(!options){
   // for security we need to check that this command runned only by lib
   // user can not run command with options
   return
}

Bot.sendMessage("Payment completed");

let amount = options.amount1;

let res = Libs.ResourcesLib.userRes("balance");
res.add(amount)

Bot.sendMessage("added to balance, BTC: " + amount);
```

### Finished!

Now you can  receive payments

### Information about extra payments and refunds.

It is possible to define buyer email in fields for options ([see](https://help.bots.business/libs/coinpayments#command-pay) code for command /pay )

{% hint style="danger" %}
**Please note:** CoinPayments do not send you extra payments. CoinPayments send just email to buyer (or you) about refund for that extra.

Also no any information about such extra in CP Panel or IPN. Be careful
{% endhint %}

### Additional Information

You can check payment status

```javascript
Libs.CoinPayments.getTxInfo({
  payment_index: payment_index,  // see /onCreatePayment command.
                                    // Need pass this payment_index to this command
  onSuccess: '/on_txn_id'
})
```

#### `command: /on_txn_id:`&#x20;

```javascript
// You can inspect all options:
// Bot.sendMessage(inspect(options));

Bot.sendMessage(options.result.status_text);

// Do not finish payment here.
// Use /onPaymentCompleted for this
```

#### `command /onIPN`

You can get info from IPN. Really it is not needed in simple. Just use onPaymentCompleted option on createTransaction.

```javascript
// You can inspect all fields:
// Bot.sendMessage(inspect(options))

// IPN is not needed
// Use - onPaymentCompleted

Bot.sendMessage("IPN: Payment status: " + options.status_text );

```

#### `command onError`

```javascript
// You can inspect all fields:
Bot.sendMessage(inspect(options))
```

###

## Permanent wallet

We use command "get\_callback\_address" with IPN.

Please see <https://www.coinpayments.net/apidoc-get-callback-address> for details.

Yes, you can write it via `Libs.CoinPayments.apiCall`method too. But there is an easier way.

### Command `/createWallet`

```javascript
Libs.CoinPayments.createPermanentWallet({
  currency: "BTC",
  //label: "myLabel",
  onSuccess: "/onWalletCreate",
  
  // onIPN - not necessary
  //onIPN: "/onPermanentWalletIPN",
  
  onIncome: "/onIncome"
  
  // if you want customize error messages
  // onError: "/onError"
});
```

{% hint style="success" %}

#### Automatically with Library:

#### CoinPayments: [IPN Retries / Duplicate IPNs](https://www.coinpayments.net/merchant-tools-ipn)

{% endhint %}

{% hint style="info" %}
It is preferable to use method  **`onIncome`** and not method **`onIPN`**.&#x20;

Since the method **`onIncome`** completely covers the IPN and solves the problem with [IPN Retries / Duplicate IPNs](https://www.coinpayments.net/merchant-tools-ipn)
{% endhint %}

### Command `/onWalletCreate`

```javascript
//Bot.sendMessage(inspect(options));

let wallet = options.result.address;
Bot.sendMessage("Your permanent wallet address is:\n`" + wallet + "`")

// You can save wallet
//User.setProperty("wallet", wallet, "string");
```

### Command `/onIncome`

```javascript
// anybody can run /onIncome command!

if(!options){
   // for security we need to check that this command runned only by lib
   // user can not run command with options
   return
}

let wallet = options.address;
let currency = options.currency;
let amount = options.amount;

let fiat_amount = options.fiat_amount;
let fiat_currency = options.fiat_coin;

let fee = options.fee;

let txn_id = options.txn_id

// see another fields by
// Bot.sendMessage(inspect(options));

Bot.sendMessage(
   "*Income to wallet:*" +
   "\n`"+ wallet + "`" +
   "\n\n*Amount*:\n" +
amount + " " + currency + " (" + fiat_amount + " " + fiat_currency + ")" +
   "\n*Fee*: " + fee +
   "\n\nTXN: `" + txn_id + "`"
);

```

#### `command onError`

```javascript
// You can inspect all fields:
Bot.sendMessage(inspect(options))
```

## Troubleshooting & Debuging

* Do not use same CoinPayment account for receiving and transfering funds.
* Go to [page](https://www.coinpayments.net/index.php?cmd=acct_balances\&action=deposits). This list must have history with completed income transaction(s)
* Try to resend IPN - see Debuging
* Verify that you have [set IPN secret](https://help.bots.business/libs/coinpayments#set-ipn-secret)

### IPN History

You can view IPN History by link <https://www.coinpayments.net/acct-ipn-history>

![](/files/-LhASv4YuoRUtMv9v4W9)

Also you can resend IPN by checkin "Resend" checkbox and button "Re-send checked IPN(s)"

### Test methods

#### Temporary wallet:

Also it is possible **make test onPaymentCompleted** event. It is good if you do not want make test payment.

```javascript
options = {
  onPaymentCompleted: "/onPaymentCompleted 0.75"
}

Libs.CoinPayments.callTestPaymentCompleted(options);
```

####

#### Permanent wallet:

Also it is possible **make test** callTestPermanentWalletIncome event. It is good if you do not want make test payment.

```javascript
options = {
  // onIPN: "/onPermanentWalletIPN",  // if you need IPN also
  onIncome: "/onIncome",
  
  // not necessary options
  // you can pass amount
  //amount: 0.5
  // txn_id: YOUR_TXN_ID
}

Libs.CoinPayments.callTestPermanentWalletIncome(options);
```

## Security

{% hint style="warning" %}
It is strongly recommended to pay attention to safety when using this library.
{% endhint %}

**Do not use default names** for secure commands such as `/onIncome`, `/onPaymentCompleted`

Anybody can run any command by names. So need to check that security command runned by CoinPayment Lib only!

```javascript
if(!options){
   // for security we need to check that this command runned only by lib
   // user can not run command with options
   return
}

// your secure code
...
```

{% hint style="danger" %}
Do not use any non official libs now.&#x20;

* Any lib can run command with options.
* Any libs can read properties (and read your API Keys from other lib)

We have not way to protect this now. Just **not use NON official libs** with CP lib. Well, that now there are no such libraries
{% endhint %}

**Grant only the really necessary permissions for the Api key.** If yor bot do not need "create\_withdrawal" or etc methods - turn theys off.&#x20;

![Check all options what you need](/files/-Leebe8uO7kxfCmAhQTQ)

Read more about security [here](https://help.bots.business/scenarios-and-bjs/bjs-security)

### Do not process any before payment!

Any API commands can have errors: API errors, timeout errors, network errors, and other errors.

You need to withdraw, make deposit income only on success!

Because if you get an error, such a conclusion, replenishment of the deposit, etc. - will always be!

![Here the balance will always be replenished, even if half of the Internet falls](/files/-M_yHcN2L5iUQu99U9A1)


# OxaPay

## 🔐 Introduction

[**OxaPay**](https://oxapay.com/?ref=53389) is a fast, secure, and developer-friendly **crypto payment gateway** that allows businesses and platforms to seamlessly accept, send, and swap cryptocurrencies. This integration empowers you to provide efficient, secure, and quick transactions, all without the need for extensive KYC procedures.

### With OxaPay, you can:

* ✅ Accept crypto payments from customers
* 💵 Send payouts to users, freelancers, or partners
* 🔁 Instantly swap between cryptocurrencies
* 🔧 Integrate everything easily via RESTful APIs

***

## 🌐 Key Features

### 💸 Payment

**Accept Crypto Payments from Customers**\
Seamlessly accept cryptocurrency payments via auto generated wallet addresses or invoice links.

* Instant wallet address generation
* White-label support for custom branding
* Invoice link
* Real-time webhook notifications
* Multi-currency & multi-network support

***

### 💵 Payout

**Send Crypto Instantly**\
Automate payouts in crypto to anyone, anywhere.

* Fast and secure transfers
* Real-time webhook notifications
* Great for affiliate systems, rewards, freelancers

***

### 🔁 Swap

**Instant Crypto Exchange**\
Convert one crypto to another instantly and securely.

* Real-time rates
* Transparent conversion
* Supports multiple crypto

***

## ⚡️ Why OxaPay?

* ✅ No complex KYC
* 🔐 Secure & reliable API
* 🚀 Fast setup and integration
* 📞 24/7 dedicated support

***

> 🔗 Learn more at [oxapay docs](https://docs.oxapay.com/)

## 🚀 Getting Started

To get started with the Bots.business integration with OxaPay, follow these steps:

1. Generate an OxaPay account and obtain your API key by referring to the [OxaPay Integrations](https://docs.oxapay.com/introduction/integrations).
2. Set your generated API keys with the following sample codes:

```javascript
//set your merchant api key
Libs.OxaPayLibV1.setMerchantApiKey("YOUR_MERCHANT_KEY");

//set your payout api key
Libs.OxaPayLibV1.setPayoutApiKey("YOUR_PAYOUT_API_KEY");

//set your general api key
Libs.OxaPayLibV1.setGeneralApiKey("YOUR_GENERAL_API_KEY");
```

3. Install the ***Webhook Library*** from the Bots.business library store to receive real-time payment and payout notifications (callback data).

## ⚙️ Calling API Method

You can interact with the OxaPay API by using the `apiCall` method. This method accepts four parameters:

* `url`: Specify OxaPay endpoints, such as '/payment/invoice' or '/payout' (refer to the [OxaPay documentation](https://docs.oxapay.com/api-reference) for a full list of endpoints).
* `method`: Specify the HTTP method for the request, either `POST` or `GET`, depending on the API endpoint requirements.
* `fields`: Provide an object containing input parameters relevant to the chosen endpoint. Refer to the API documentation for specific details.
* `on_success`: Define your custom logic to handle the output of the method.

## 🌐 Available URLs

### 💸 Payment Endpoints

| Endpoint                       | Method | Description                            |
| ------------------------------ | ------ | -------------------------------------- |
| /payment/invoice               | POST   | Create a payment invoice               |
| /payment/white-label           | POST   | Generate white-label payment           |
| /payment/static-address        | POST   | Create static wallet address           |
| /payment/static-address/revoke | POST   | Revoke a static address                |
| /payment/{track\_id}           | GET    | Retrieve payment details by track ID   |
| /payment                       | GET    | Get a list of all your payment records |
| /payment/accepted-currencies   | GET    | List of your allowed cryptocurrencies  |

### 💵 Payout Endpoints

| Endpoint            | Method | Description                           |
| ------------------- | ------ | ------------------------------------- |
| /payout             | POST   | Send crypto payments                  |
| /payout/{track\_id} | GET    | Retrieve payout details by track ID   |
| /payout             | GET    | Get a list of all your payout records |

### 🔁 Swap Endpoints

| Endpoint                | Method | Description                                        |
| ----------------------- | ------ | -------------------------------------------------- |
| /general/swap           | POST   | Create a new crypto swap request                   |
| /general/swap           | GET    | Get a list of your swap history                    |
| /general/swap/pairs     | GET    | Get a list of supported currency swap pairs        |
| /general/swap/calculate | POST   | calculate output amount for a given swap request   |
| /general/swap/rate      | POST   | Get real-time exchange rate between two currencies |

### 📚 Common Endpoints

| Endpoint                 | Method | Description                        |
| ------------------------ | ------ | ---------------------------------- |
| /general/account/balance | POST   | Get your current account balance   |
| /common/prices           | GET    | Get real-time crypto prices        |
| /common/currencies       | GET    | List supported cryptocurrencies    |
| /common/fiats            | GET    | List supported fiat currencies     |
| /common/networks         | GET    | List supported blockchain networks |

Feel free to explore these endpoints to build powerful crypto payment solutions with Bots.business and OxaPay.

## 📝 Examples

Explore practical examples of integrating Bots.business with OxaPay.

### Payment Example: Create White Label

* Execute the `paytrx` command to create a white-label payment.
* Provide necessary options such as amount, currency, pay\_currency, lifetime, order\_id, and on\_callback.
* The `onCreatePaymentWithTRX` command handles the output, generating a QR code and providing payment details.

Command ***/payTrx***

```javascript
let options = {
	url: "/payment/white-label",
	method: "POST",
	fields: {
		amount: 100,
		currency: 'USD',
		pay_currency: "TRX",
		network: "TRC20",
		lifetime: 60,
		fee_paid_by_payer: 1,
		under_paid_coverage: 20,
		to_currency: "USDT",
		auto_withdrawal: false,
		email: "customer@oxapay.com",
		order_id: "ORD-12345",
		description: "Order #12345",
		on_callback: "/onCallbackPayment"
	},
	on_success: "/onCreatePaymentWithTRX"
}
Libs.OxaPayLibV1.apiCall(options)
```

Command ***/onCreatePaymentWithTRX***

```javascript
if (!options) { return }

if (options.status!= 200) {
  // not success
  Bot.sendMessage(options.error?.message || options.message);
  return
}

let toDate = new Date(options.data.expired_at * 1000).toISOString();

let caption = 
  "📨 Address: <code>" + options.data.address + "</code>" +
  "<br>💰 Coin: <b>" + options.data.currency + "</b>" +
  "<br>🌐 Network: <b>" + options.data.network + "</b>" +
  "<br>💵 Amount: <code>" + options.data.pay_amount + "</code> " + options.data.pay_currency +
  "<br><br>‼️ Sending less may result in fund loss!" +
  "<br>‼️ Please only send <b>" + options.data.currency + "</b> on <b>" + options.data.network + "</b> network." +
  "<br>⏰ Expiry: " + toDate;

Api.sendPhoto({
  photo: options.data.qr_code,
  caption: caption,
  parse_mode: "HTML",
});
```

#### Payment Callback

* When payment status changes, the `/onCallbackPayment` command processes the status and notifies users accordingly.

Command ***/onCallbackPayment***

```javascript
if (!options) return;

const ADMIN_TELEGRAM_ID = "PUT YOUR TELEGRAM ID HERE";

if (options.status == "paying"){
  Bot.sendMessage(
    `📢 Your paid ${options.amount} ${options.currency} is confirming...`
  );
}else if (options.status == "paid") {
  Bot.sendMessage(`✅ Your payment was successful.`);
}

Api.sendMessage({
  chat_id: ADMIN_TELEGRAM_ID,
  text: "📢 Your invoice with trackId " + 
      `${options.track_id} and orderId ${options.order_id} ${options.status}`
});
```

### Payout Example: Generate Payout

* Use the `transfer` command to initiate a payout.
* Specify options like amount, currency, address, and on\_callback.
* The `onTransfer` command captures the result, notifying users about the payout status.

Commend ***/transfer***

```javascript
let amount = 10;
let options = {
  url: "/payout",
  method: "POST",
  fields: {
    amount: amount,
    currency: "TRX",
    network: "TRC20",
    address: "RECEIVER_ADDRESS",
    on_callback: "/onCallbackPayout",
    description: "Order #12345"
  },
  on_success: "/onTransfer " + amount +" TRX",
};
Libs.OxaPayLibV1.apiCall(options);
```

Command ***/onTransfer***

```javascript
if (!options) return;
if (options.status == 200){
  Bot.sendMessage(
    `✅ Send request submitted successfully!\nTrack ID: ${options.data.track_id}`
  );
} else {
  Bot.sendMessage(`❌ Your send request failed. ${options.error?.message || options.message}`);
}

if (options.data.status == "confirmed"){
  Bot.sendMessage("✅ Your transfer was successful.");
}
```

### Payout Callback

* The `/onCallbackPayout` command reacts to payout status changes and keeps users informed.

Command ***/onCallbackPayout***

```javascript
if (!options) return

const ADMIN_TELEGRAM_ID = 'PUT YOUR TELEGRAM ID HERE'

if (options.status == 'Confirming'){
  Bot.sendMessage(`📢 Your withdrawal is confirming...`)
} else if(options.status == 'Confirmed'){
  Bot.sendMessage(`✅ Your withdrawal was successfully completed!`)
}

Api.sendMessage({
  chat_id: ADMIN_TELEGRAM_ID,
  text: `📤 Withdrawal Alert:\nAmount: ${options.amount} ${options.currency}\nStatus: ${options.status}`
})
```

### Swap Example: Swap Request

* Execute the command `swapBtc`.
* Provide necessary options such as amount, from\_currency and to\_currency.
* The `onSwapResponse` command will handle the API response.

Command ***/swapBtc***

```javascript
let options = {
  url: "/general/swap",
  method:"POST",
  fields: {
	amount: 0.5,
	from_currency: "BTC",
	to_currency: "USDT",
  },
  on_success: "/onSwapResponse",
};
Libs.OxaPayLibV1.apiCall(options);
```

Command ***/onSwapResponse***

```javascript
if (!options) return;
if (options.status == 200){
  Bot.sendMessage(
    `✅ Your swap request was successful!\nTrack ID: ${options.data.track_id}`
  );
} else {
  Bot.sendMessage(`❌ Your swap request failed. ${options.error?.message || options.message}`);
}
```


# CryptoJS

JavaScript library of crypto standards. It is **included by default** - installation is not required.

## Usage

```javascript
var hash = CryptoJS.HmacSHA1("Message", "Key")
Bot.sendMessage(String(hash));

hash = CryptoJS.HmacSHA256("Message", "Secret Passphrase");
Bot.sendMessage(String(hash));
```

**Documentation**: [https://cryptojs.gitbook.io/docs](https://cryptojs.gitbook.io/docs/)


# CurrencyQuote

JavaScript library of currency quotes. It is **included by default** - installation is not required.

It is have currencies and crypto currencies (top 100 list)

**Update time:**

* currencies update time is: once at 1 hour
* crypto currencies update time is: once at 5 minutes

{% hint style="warning" %}
Possibly longer update times due to network errors and other errors.

But you can [check](/libs/currencyquote#check-last-updated-time) this.
{% endhint %}

## Usage

Get prices:

```javascript
// get EUR / USD cost
var eur_price = CurrencyQuote.fiat.EUR;
var btc_price = CurrencyQuote.crypto.BTC;
```

Get crypto details:

```javascript
// get EUR / USD cost
var btcDetails = CurrencyQuote.crypto.details.BTC;
Bot.inspect(btcDetails)

/* result:
{
  "id": 1,
  "name": "Bitcoin",
  "symbol": "BTC",
  "slug": "bitcoin",
  "num_market_pairs": 9189,
  "date_added": "2013-04-28T00:00:00.000Z",
  "tags": [
    "mineable",
    "pow",
    "sha-256",
    ...
  ],
  "max_supply": 21000000,
  "circulating_supply": 18741687,
  "total_supply": 18741687,
  "platform": null,
  "cmc_rank": 1,
  "last_updated": "2021-06-24T11:03:02.000Z",
  "quote": {
    "USD": {
      "price": 33330.324732476154,
      "volume_24h": 33455787206.23486,
      "percent_change_1h": -0.01335238,
      "percent_change_24h": -2.7360215,
      ...
      "market_cap": 624666513744.4268,
      "last_updated": "2021-06-24T11:03:02.000Z"
    }
  }
}

*/
```

Convertation:

```javascript
// convert 15 EUR to TRX
var trx = CurrencyQuote.convert({ amount: 15, from: "EUR", to: "TRX" })

// from 0.1 BTC to INR
var inr = CurrencyQuote.convert({ amount: 0.1, from: "BTC", to: "INR" })
```

## Check last updated time

```javascript
// update time in seconds
// max time in normal 3600 seconds
var secsFiat = CurrencyQuote.fiat.getCachingTime();
var secsCrypto = CurrencyQuote.crypto.getCachingTime();

var oneHour = 60*60;
if(secsCrypto > oneHour){
   // it is very old data! Last updated a hour ago
   Bot.sendMessage("Please try later")
   return
}

var oneDay = oneHour*24;
if(secsFiat > oneDay){
   // it is very old data! Last updated a day ago
   Bot.sendMessage("Please try later")
   return
}

// get EUR
var eur_price = CurrencyQuote.fiat.EUR;
var btc_price = CurrencyQuote.crypto.BTC;
```


# GoogleApp

Use this lib to connect BJS with [Google App Script](https://developers.google.com/apps-script)

![](/files/-MG811nMSXwLiCzb5OKb)

## Getting started

### **Easy setup**

1. Copy this [table](https://docs.google.com/spreadsheets/d/1aOIYlwRqiCFWxeTTkhE31pBFTOeByrl3FRusGc1pZZ0/edit#gid=0) to your Google account
2. [Deploy](#3.-deploy-as-web-app) as web app
3. Try to open web app via app [Public App url](#4.-public-app-url)
4. Install *GoogleAppLib* and *WebhooksLib* to your bot
5. Create [setup](#7.-create-setup-command) command

After this step you can [use](#using) this Lib and [debug](#debugging).

###

### **Detail setup**

{% hint style="info" %}
This is detail setup description. Please try to use [easy setup](#easy-setup) before it.
{% endhint %}

#### **1. Create new App Script project**

Go to <https://script.google.com> and create new project by button:

![](/files/-MG81efFz8LK3N3yndQs)

#### 2. Add Code.gs

Paste the script from [above](https://github.com/bots-business/store-libs/blob/master/GoogleAppSync.gs) into the script code editor and hit *Save.*

![](/files/yt18F88LSfZBxIDkrXXE)

You will need to contact your Google Apps administrator, or else use a Gmail account.)

#### **3. Deploy as web app**

Now click *Deploy*. You may be asked to review permissions now. **Project version** - always "New".

![](/files/x5stNGbXnHA6gMJMPlYK)

Cloick in Deploy button. You will have Public App url.

#### 4. Public App URL

The URL that you get will be the webhook that you need use in this Lib. You can test this webhook in your browser first by pasting it. Note that depending on your Google Apps instance, you may need to adjust the URL to make it work.&#x20;

#### 5. Add permissions

You need to add [permissions](#permissions)

#### 6. Install *GoogleAppLib* and *WebhooksLib* to bot

Go to App > Libs and install *GoogleAppLib* and *WebhooksLib*&#x20;

#### 7. Create setup command:

**`/setup`**

```javascript
// replace with your URL, obtained in step 4
Libs.GoogleApp.setUrl("https://script.google.com/macros/*******");
```

## Using

Use any Google App script in BJS now

```javascript
function GACode(){
   // Google App Script code here
   // Please note: this function is runs on GA not BB
   // ...
}

// BJS
Libs.GoogleApp.run({
  code: GACode, // Function with Google App code
  onRun: "onRun", // Optional. This command will be executed after run
  email: "my@email.com" // Optional. Email for errors,
  // debug: true // For debug. Default is false
});
```

Example for command `/task`

```javascript
function GACode(){
  // translation from English to France
  var trans = LanguageApp.translate(params, 'en', 'fr');

  // make Google Calendar event
  var event = CalendarApp.getDefaultCalendar()
    .createEventFromDescription('Lunch with ' + user.first_name + ', Friday at 1PM');
  
  // send Email
  MailApp.sendEmail({
    to: "help@example.com",
    subject: "hello from bot " + bot.name,
    htmlBody: "<h1>Hello!</h1>How are you?<br>" +
        "We have message to bot: " + message
  });

  // ...
  // Use all power of Google App Script!
  
  // return result as JSON
  return { event: event, trans: trans }
}

Libs.GoogleApp.run({
  code: GACode,
  onRun: "onRun",
  // email: "test@example.com" // email for errors
  // debug: true // default false
});
```

{% hint style="warning" %}
You can turn on debug flag with true

Then you can [debug](#debugging) code
{% endhint %}

command `onRun`

```javascript
Bot.sendMessage(inspect(options))
```

{% hint style="warning" %}
**GACode** - it is isolated function with Google App code. It can not have BJS code like `Bot.sendMessage` and etc. Only GA code!

**But you can** use [variables](/bjs/variables) and pass data with [options](/bjs/bot-functions#bot-run-options) for Bot.run method.

```javascript
let myVar = "will not works";

options.myVar = "will be works";

function GACode(){
   // Google App Script code here
   // Please note: this function is runs on GA not BB
   // ...
   
   myVar = 5; // Error! myVar is not defined in GA only in BB side
   
   // this will be works:
   let myVar;
   myVar = 5;
   
   Bot.sendMessage("ok")  // Error! It is BJS not GA code!
   
   let botName = bot.name; // Will be worked
   let myVar = options.myVar; // Will be worked
}
```

{% endhint %}

## Permissions

{% hint style="warning" %}
You need set permissions for Google App Script
{% endhint %}

Run `Libs.GoogleApp.run()`in first time. You can have like such error:

> Error on Google App script: "Exception"
>
> "The script does not have permission to perform that action. Required permissions: (<https://www.googleapis.com/auth/calendar> || <https://www.googleapis.com/auth/calendar.readonly> || <https://www.google.com/calendar/feeds>)"

If you have such error you need set access rights.

### Granting access rights via manifest file

Full help available [here](https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes). From that help:

1. Open the script project.
2. At the left, click **Project Settings** settings.
3. Select the **Show "appsscript.json" manifest file in editor** checkbox:

![](/files/AiBb1h0HK5cgdQDZhmzj)

At the left, click **Editor** code.

At the left, click the `appsscript.json` file.

Locate the top-level field labeled `oauthScopes`. If it's not present, you can add it.

The `oauthScopes` field specifies an array of strings. To set the scopes your project uses, replace the contents of this array with the scopes you want it to use. For example:

```
{
  "timeZone": "Asia/Tokyo",
  "dependencies": {
  },
  "webapp": {
    "access": "ANYONE_ANONYMOUS",
    "executeAs": "USER_DEPLOYING"
  },
  "exceptionLogging": "STACKDRIVER",
  "oauthScopes": ["https://www.googleapis.com/auth/script.send_mail",
                  "https://www.googleapis.com/auth/script.external_request",
                  "https://www.googleapis.com/auth/spreadsheets"],
  "runtimeVersion": "V8"
}
```

1. <https://www.googleapis.com/auth/script.send_mail>", "<https://www.googleapis.com/auth/script.external_request> - is mandatory scope
2. Save the manifest file using **Ctrl+S** or the Save file icon in the menu bar.
3. Publish your app again (see [step 3](/libs/googleapp#getting-started))

![](/files/-MH-AT1ETFDtLKZ3WWX8)

## Debugging

Run `Libs.GoogleAppLib.run`in first time. Then:

* go to Google App Script Editor (See [step 2](/libs/googleapp#getting-started))
* select "debug" function on Tab
* press "Debug" button:

![](/files/ZQ1NZmZPUuDoJGQD52f4)

Google app is runs. Bot will sent execution result to you. Also you can receive email with error description.

{% hint style="success" %}
You can use "debug" function anytime for debugging
{% endhint %}

Also you can open web app by url (see [step 5](#getting-started)) in incognito mode. And look for any errors. For example we have permission error here:

![](/files/rHyxNevhG0fS3Ye4juWc)

## Links

[Google App script](https://developers.google.com/apps-script) home page

Google App Script [examples](https://github.com/gsuitedevs/apps-script-samples) - good examples for inspiration

Stack Overflow [answers](http://stackoverflow.com/questions/tagged/google-apps-script) - ask your questions on SO

[Videos](https://developers.google.com/apps-script/guides/videos) -  Check out the Apps Script videos on YouTube

[Reference](https://developers.google.com/apps-script/reference) - The reference documentation provided in this section describes the various Apps Script services and the Apps Script manifest file structure.


# GoogleTableSync

You can post, update and read data from GoogleSpreadSheet with this lib.

![](/files/ohTXR37qUunq9JDno10J)

### Setup

1\. Please see setup for [GoogleApp lib](/libs/googleapp). This lib requires GoogleApp lib.

2\. Create blank Google table. You don't need any headers. Headers will be added automatically.

3\. Also you need to run code too:

`Libs.GoogleApp.setUrl("https://script.google.com/*************/exec");`

{% hint style="info" %}
If you have any problems with this lib - use help from [GoogleApp lib](/libs/googleapp).
{% endhint %}

### Demo bot

{% embed url="<https://telegram.me/BBGoogleSpreadsheetBot>" %}

### Write or update data

{% hint style="success" %}
Use `index` for magic!

With index key exist row will be updated!
{% endhint %}

You need tableID. You can get it from table url. It is selected here:

![](/files/hWhnmVXo9QrJpw2ZjX5A)

```javascript
Bot.sendMessage("Saving...");

var syncOptions = {
  tableID: "1_NldI2**********ank1B9c",
  sheetName: "Users",
  // this column will be used as index for updates or reading
  index: "id",
  // store data
  datas: [],
  // this command will be runned after sync
  onRun: "/onSync",

  // for debug. Comment this lines
  // email: "hello@bots.business",
  // debug: true
}

user.balance = User.getProperty("balance");

syncOptions.datas[0] = user;

// you can add more records with index 
// syncOptions.datas[1] and etc 

Libs.GoogleTableSync.sync(syncOptions);
```

{% hint style="success" %}
You can store any data like users, chats, products, resources and etc
{% endhint %}

```javascript
Bot.sendMessage("Saving...");

var syncOptions = {
  tableID: "1_NldI2**********ank1B9c",
  sheetName: "Orders",
  // this column will be used as index for updates or reading
  index: "orderId",
  datas: [],
  // this command will be runned after sync
  onRun: "/onSync"
}

var order = {
   orderId: 10,
   title: "Order - " + String(user.id),
   amount: 15
}

syncOptions.datas.push(order);
Libs.GoogleTableSync.sync(syncOptions);
```

### Read data

```javascript
Bot.sendMessage("Reading...");

var syncOptions = {
  tableID: "1_NldI2**********ank1B9c",
  sheetName: "Users",
  // this column will be used as index for updates or reading
  index: "id",
  // reading data
  datas: [],
  // this command will be runned after sync
  onRun: "/onSync",

  // for debug. Comment this lines
  // email: "hello@bots.business",
  // debug: true
}

syncOptions.datas[0] = user;
// also you can use something like:
// syncOptions.datas[0] = { id: any_user_id }

// you can add more records with index 
// syncOptions.datas[1] and etc 


Libs.GoogleTableSync.read(syncOptions)
```

### Command /onSync

`Bot.inspect(options)`


# Guard

Gives access to individual commands only to admins.

Initial setup:

* Install Library
* Сreate `/setup` command:

```javascript
Libs.Guard.setup();
```

You will have such admin panel:

![](/files/Dorrb9aSdcroCBxfJKHq)

* Create the @ command or add to an existing one the following code (at the very beginning):

```
if (!Libs.Guard.verifyAccess()) return;
```

Add the commands you want to restrict access to to the "admins" folder (by default).

You can add/remove admins, change the folder for admin commands and add a command for unauthorized access attempts in the admin panel:&#x20;

`App > Bot > Admin Panels > Guard.`

### Checking access

{% hint style="success" %}
Just put all your admin commands in one folder.

The check will be automatic.
{% endhint %}

For manuall checking mode use:

```javascript
if (Libs.Guard.isAdmin(user.id)){
   // admin
}else{
   // not admin
}
```


# Webhooks lib

Integration with external services can be possible with webhooks notifications. This lib generate url for webhooks.

## Example bot

See [example bot](https://t.me/BBWebhookBot)

{% hint style="info" %}
From [wikipedia](https://en.wikipedia.org/wiki/Webhook): a **webhook** is a method of augmenting or altering the behavior of bot, with custom [callbacks](https://en.wikipedia.org/wiki/Callback_\(computer_programming\)).

These callbacks may be maintained, modified, and managed by third-party users and developers who may not necessarily be affiliated with the originating website or application.

&#x20;The term "webhook" was coined by Jeff Lindsay in 2007 from the computer programming term [hook](https://en.wikipedia.org/wiki/Hooking).
{% endhint %}

Webhooks is more simple way for integration. Other libs also use webhooks notifications already: CoinPayments, FreeKassa.

{% hint style="success" %}
Webhook link have public\_user\_token - it is public secret.

User can't modify user\_id, command because it is protected with public\_user\_token.
{% endhint %}

## Get Webhook Url

```javascript
// user's webhook
let webhookUrl = Libs.Webhooks.getUrlFor({
  // this command will be runned on webhook
  command: "/onWebhook",
  // this text will be passed to command
  content: "Did you see the cat?",
  // execute for this (current) user
  user_id: user.id,
  // redirect to page with cat after calling webhook
  // you need remove this for external service
  redirect_to: "https://cataas.com/cat"
})

Bot.inspect(webhookUrl);
```

This code will generate Webhook url.&#x20;

After loading page via this url:

* web page with cat will be loaded (Thank for cat to [https://cataas.com](https://cataas.com/cat))
* command `/onWebhook` will be execute on Bot for user with user.id
* content "Did you see the cat?" will be passed for command `/onWebhook`

### &#x20;

## Receive webhook for user

As a rule, the webhook URL must be set from the admin panel on the external service. So we can not set it for just one user:&#x20;

```javascript
// global bot webhook
let webhookUrl = Libs.Webhooks.getUrlFor({
  // this command will be runned on webhook
  command: "/onWebhook",
  user_id: user.id
})
```

{% hint style="warning" %}
Webhooks can be with GET and POST methods only. All passed data contains on content variable
{% endhint %}

On command `/onWebhook` we can get posted content from external service

```javascript
// for user's webhook
Bot.sendMessage(inspect(content))
// also you can read data with Bot.getProperty - you need store it before
```

As a rule, external service must pass useful data on webhook. For example info about payments: order\_id, user\_id. Use it!

## Receive global webhook for bot

On command `/onWebhook` for bot's webhook we do not have user:

```javascript
// for bot's webhook

// this is not worked - because no current user on bot's webhook
// Bot.sendMessage(inspect(content))

// make any not specific user code
// ...

// We can pass user_id in content (it is depend from external service)
Bot.run({
   command: "/userCommand",
   user_id: JSON.parse(content).user_id
})

// in /userCommand we can now use Bot.sendMessage function

```

## Call options

You can use options on BJS on webhook request

`/onWebhook` command:

```javascript
Bot.sendMessage(
  JSON.stringify(options)
);
```

| Key               | Value                                                                  |
| ----------------- | ---------------------------------------------------------------------- |
| `options.url`     | webhook url                                                            |
| `options.method`  | request method ("GET" or "POST")                                       |
| `options.params`  | request params                                                         |
| `options.headers` | headers for this request like Ip,  User-Agent, Accept-Language and etc |
| `options.ip`      | client IP                                                              |

## Webhook response

### 1. Content response with bot answer

```javascript
// call user's webhook
// first message sending appears on bot
Bot.sendMessage("This answer will be in bot");

//...
// last message sending
// will be on bot and on web page
// you can open this web page on your browser via webhook url

Bot.sendMessage("Hello in browser!");

// in web page you will have:
// { answer: "Hello in browser!" }
```

### 2. Content response without bot answer

You can use [WebApp](/bjs/web-app) render - it is not produce message from bot.

```javascript
// render this command in web
WebApp.render({ content: "Hello from bot " + bot.name });
```

### Code response

Webhook response can be:

* 200 - BJS is runned, no errors
* 503 - we have errors in BJS

you can throw error in BJS:

`throw new Error("Error on webhook")`

## Possible issues

In the case of a large number of requests from an external web service, such a web service may be subject to ban filters.

Please provide an external IP address and we will add it to the White List.


# DateTimeFormat Lib

Convert time to time string by mask.

Implemented from <http://blog.stevenlevithan.com/archives/date-time-format>

```javascript
Libs.DateTimeFormat.format(time, mask);
```

Example:

```javascript
var now = new Date();
Libs.DateTimeFormat.format(now, "m/dd/yy");

Libs.DateTimeFormat.format(now, "ddd mmm dd yyyy HH:MM:ss");

Libs.DateTimeFormat.format(now, "h:MM TT");

```

| Mask           | Description                                                                                                                                                                                       |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `d`            | Day of the month as digits; no leading zero for single-digit days.                                                                                                                                |
| `dd`           | Day of the month as digits; leading zero for single-digit days.                                                                                                                                   |
| `ddd`          | Day of the week as a three-letter abbreviation.                                                                                                                                                   |
| `dddd`         | Day of the week as its full name.                                                                                                                                                                 |
| `m`            | Month as digits; no leading zero for single-digit months.                                                                                                                                         |
| `mm`           | Month as digits; leading zero for single-digit months.                                                                                                                                            |
| `mmm`          | Month as a three-letter abbreviation.                                                                                                                                                             |
| `mmmm`         | Month as its full name.                                                                                                                                                                           |
| `yy`           | Year as last two digits; leading zero for years less than 10.                                                                                                                                     |
| `yyyy`         | Year represented by four digits.                                                                                                                                                                  |
| `h`            | Hours; no leading zero for single-digit hours (12-hour clock).                                                                                                                                    |
| `hh`           | Hours; leading zero for single-digit hours (12-hour clock).                                                                                                                                       |
| `H`            | Hours; no leading zero for single-digit hours (24-hour clock).                                                                                                                                    |
| `HH`           | Hours; leading zero for single-digit hours (24-hour clock).                                                                                                                                       |
| `M`            | <p>Minutes; no leading zero for single-digit minutes.<br>Uppercase M unlike CF <code>timeFormat</code>'s m to avoid conflict with months.</p>                                                     |
| `MM`           | <p>Minutes; leading zero for single-digit minutes.<br>Uppercase MM unlike CF <code>timeFormat</code>'s mm to avoid conflict with months.</p>                                                      |
| `s`            | Seconds; no leading zero for single-digit seconds.                                                                                                                                                |
| `ss`           | Seconds; leading zero for single-digit seconds.                                                                                                                                                   |
| `l` *or* `L`   | Milliseconds. `l` gives 3 digits. `L` gives 2 digits.                                                                                                                                             |
| `t`            | <p>Lowercase, single-character time marker string: <em>a</em> or <em>p</em>.<br>No equivalent in CF.</p>                                                                                          |
| `tt`           | <p>Lowercase, two-character time marker string: <em>am</em> or <em>pm</em>.<br>No equivalent in CF.</p>                                                                                           |
| `T`            | <p>Uppercase, single-character time marker string: <em>A</em> or <em>P</em>.<br>Uppercase T unlike CF's t to allow for user-specified casing.</p>                                                 |
| `TT`           | <p>Uppercase, two-character time marker string: <em>AM</em> or <em>PM</em>.<br>Uppercase TT unlike CF's tt to allow for user-specified casing.</p>                                                |
| `Z`            | <p>US timezone abbreviation, e.g. <em>EST</em> or <em>MDT</em>. With non-US timezones or in the Opera browser, the GMT/UTC offset is returned, e.g. <em>GMT-0500</em><br>No equivalent in CF.</p> |
| `o`            | <p>GMT/UTC timezone offset, e.g. <em>-0500</em> or <em>+0230</em>.<br>No equivalent in CF.</p>                                                                                                    |
| `S`            | <p>The date's ordinal suffix (<em>st</em>, <em>nd</em>, <em>rd</em>, or <em>th</em>). Works well with <code>d</code>.<br>No equivalent in CF.</p>                                                 |
| `'…'`*or*`"…"` | <p>Literal character sequence. Surrounding quotes are removed.<br>No equivalent in CF.</p>                                                                                                        |
| `UTC:`         | <p>Must be the first four characters of the mask. Converts the date from local time to UTC/GMT/Zulu time before applying the mask. The "UTC:" prefix is removed.<br>No equivalent in CF.</p>      |


# BB Point Bot

BB Point bot helps develop the community. User can echange BB Points to Extra Iterations.

Also it is possible:

* Accept BB Points 💎 in your bot from users
* Transfer BB Points 💎 from your bot to users

{% hint style="success" %}
This functionality is built with [WebhookLib](/libs/webhooks-lib). You can do some pretty cool stuff in your bots to share data too.
{% endhint %}

## Accept BB Points in your bot

![](https://telegra.ph/file/31b497c82e26a1dc2d8d3.png)

We can accept BB Points 💎 in any bot now.

See example in [@BBWebhookBot](https://t.me/BBWebhookBot)

### How to make?

See example for /sample3 in [@BBWebhookBot](https://t.me/BBWebhookBot)

#### Step 1

Install Webhook Lib in your bot and make webhook url:

```javascript
// Generate webhook link for BB Point Bot
let url = Libs.Webhooks.getUrlFor({
 command: "onBBPointIncome"
})

Bot.sendMessage(
 "Set this url in [@BBPointBot](https://t.me/BBPointBot?start=link) " +
 "bot for notification." +
 "\n\nCommand [@BBPointBot > /link](https://t.me/BBPointBot?start=link) "
)

// send url without markup
Api.sendMessage({ text: url });
```

#### Step 2 <a href="#step-2" id="step-2"></a>

Go to [@BBPointBot](https://t.me/BBPointBot) - **/link** and paste link from step1

You will get such link for request:

<https://t.me/BBPointBot?start=req15-**1**-points-to-519829299>

> You can change **bb point** amount in url part: **-XXX-points**

> You can change **user.id** after part: -**to-user-XXX**

## Transfer BB Points 💎 from your bot to users

#### Step 1

Generate your personal secret webhook url in [@BBPointBot](https://t.me/BBPointBot) by command: `/getTransferUrl`

Set **Secret (**&#x61;ny words or symbols - whatever you wan&#x74;**)** in [@BBPointBot](https://t.me/BBPointBot) by command: `/setTransferSecret`

{% hint style="warning" %}
Personal secret webhook url with Secret - is safe information.&#x20;

You can reset the Secret at any time via command `/setTransferSecret`&#x20;
{% endhint %}

#### Step 2

In your bot command create new command `/makeTransfer`:

```javascript
// Danger! User can run this command
// You need add logic for secure
// if(your logic){ return }

// Just generate webhook url for current user
let webhookUrl = Libs.Webhooks.getUrlFor({
  command: "onTransfer",
  user_id: user.id
})

Bot.sendMessage("Transfer in progress")

// make transfer request to BB Point bot
HTTP.post( {
    url: "http://Your Personal secret webhook url from step 1",
         
    body: {
       // BB Points amount
       amount: 3,
       // transfer BB Points for current user
       to_tg_id: user.telegramid,
       // note for @bbpoints channel
       note: "#testTransfer by " + bot.name,
       webhookUrl: webhookUrl,
       secret: "your Secret" // from step 1
    }
} )

```

{% hint style="danger" %}
This command transfer BB Points without any conditions.

You must add some conditions. You are not going to send BB Points without any reason?&#x20;
{% endhint %}

**Step 3**

In your bot command create new command `onTransfer`:

```javascript
var json = JSON.parse(content);

// You can inspect all passed data:
// Bot.inspect(json)

if(json.error){
  Bot.sendMessage("Error: " + json.error.title);
  Bot.sendMessage("Code: " + json.error.code);
  // error codes:
  // 1 - You do not have BB Points for transfer
  return
}

// BB Points transferred to current user
let admin_bb_points = json.owner.bb_points - json.amount;

Bot.sendMessage(
    "BB Points transferred:\n" +
    json.amount + "💎 BB Points to tg id: " + user.telegramid + 

    "\n\nAdmin: @" + json.owner.username + 
       "\n have now: " + String(admin_bb_points) + "💎 BB Points"
)


```


# Welcome bot

This bot greeting all new members in chat and say "Good morning" every day.

### Good morning every day

We use [Auto Retry](https://help.bots.business/commands/auto-retry) for this. Every 50 minutes we check time. If current hour is 6 AM - bot send greeting message to all chat.

{% hint style="info" %}
Auto retry run periodically.

We have 50 minutes - so we iterate every hour without repeating.
{% endhint %}

Set 3000 to Auto Retry:

![](/files/-LWYnFTxGjkUumx4miJX)

#### Users can not run this command.

Bot send message to ALL chats. If user run this command at 6 AM - bot send message too!&#x20;

We need check for auto retry only. Auto Retry do not have chat variable. Execution breaks if chat exist.

```javascript
// can be runned with Auto Retry only!
if(chat){ return }
```

Then other code:

```javascript
let time = new Date()
let hours = time.getHours();
let minutes = time.getMinutes();

curTime = "Time: " + hours + ":" + minutes + " GMT-0";
msg = "";

if(hours==6){
  msg = "Good morning!\n" + curTime;
}

Bot.sendMessageToAllChats(msg);
```

### Greeting all new member

We use Master commad "\*" for this. it capture all messages.

Request can have information about new members:

```javascript
let new_members = request.new_chat_members;
```

We need build greetings for all users:

```javascript
if(new_members.length > 0){
   for(var i=0; i<new_members.length; i++){
      msg = msg + comma + getNameFor(new_members[i])
      comma = ", ";
   }
   Bot.sendMessage(msg);
}
```

User can have username or first name. Or have not:

```javascript
function getNameFor(member){
   let haveAnyNames = member.username&&member.first_name;
   if(!haveAnyNames){ return ""}

   return member.username ? ("@" + member.username) : member.first_name
}
```

#### All code:&#x20;

```javascript
let new_members = request.new_chat_members;
let msg = "Hello, ";
let comma = "";

function getNameFor(member){
   let haveAnyNames = member.username&&member.first_name;
   if(!haveAnyNames){ return ""}

   return member.username ? ("@" + member.username) : member.first_name
}

if(new_members.length > 0){
   for(var i=0; i<new_members.length; i++){
      msg = msg + comma + getNameFor(new_members[i])
      comma = ", ";
   }
   Bot.sendMessage(msg);
}

if(request.left_chat_member){
  Bot.sendMessage(
    "Goodbye, " + getNameFor(request.left_chat_member)
  );
}

```

![](/files/-LWYwkVmko0cnbiVip_d)


# Help bot

![](/files/-LWOxv17hMVWXDlFeNX2)

In Bots.Business chat we have many generic questions. [This bot](https://telegram.me/BBHelpBot) can answer for them.

Bot is [Inline bot](/bjs/inline-bot) - it can used for searching in [help.bots.business](https://help.bots.business/)

Also bot use [Master command](https://help.bots.business/commands#how-to-execute-command-with-any-text-from-user-master-command) - \*.

### Code description

Bot receive all messages from chat with Master command.

So we do not need any notifications about new chat members and etc:

```javascript
if(!message){ return }
```

{% hint style="info" %}
Do you have big case for command execution? You can use return. &#x20;
{% endhint %}

Bot have keywords for searching in user's messages. Bot show answer and url on keywoard in message:

```javascript
list = [
   { url: "status.bots.business", keywords: [ 'status' ],
       answer: 'Seems do you need to know uptime status?' },
   { keywords: [ '/start' ], answer: 'Please do not touch it here' },
   { keywords: [ 'php ', ' php' ], answer: 'PHP? Really? I love BJS only' },
   { keywords: [ 'hi!', 'hello' ], answer: 'Hey!' }
]
```

Also admin can write anything and do not need any help. So we have key - answerToAdmin:

```javascript
let admin_tg_id = 519829299;
...
{ url: "status.bots.business", keywords: [ 'status' ], answerToAdmin: true }
```

Sometimes we need exact searhing:

```javascript
{ url: "help.bots.business", keywords: [ 'help' ], exact:true}
```

Message can be in aNyCAse. We need it only in lowercase:

```javascript
let stext = message.toLowerCase();
```

We use functions in the code. So code more simple:

```javascript
// search keyword in the message (stext)
function haveAnyKeyword(item){
  for(var ind in item.keywords){
    // exact searhing
    if(item.exact){
      // exact searching
      if(stext==item.keywords[ind]){ return true }
      continue;
    }

    if(stext.indexOf(item.keywords[ind])>-1){ return true }
  }
}

// build answer
function getAnswerFor(item){
  if((user.telegramid==admin_tg_id)&&(!item.answerToAdmin)){
     // no any answer for admin
     return;
  }
  
  let answer = item.answer;
  if(!answer){ answer = "" }

  if(item.url){
    answer = answer + "\nhttp://" + item.url
  }
  return answer;
}

// just bust all keywords list 
function doSearch(){
  let item;
  let answer;

  for(var ind in list){
    item = list[ind];
    if(haveAnyKeyword(item.keywords)){
      return getAnswerFor(item);
    }
  }
}
```

{% hint style="info" %}
Functions create your code more simple. It is good for it rewriting and improvement.
{% endhint %}

Perform searching. And if we get answer - send message:

```javascript

let answer = doSearch();
if(answer){
  Bot.sendMessage(answer, {is_reply: true});
}

```

{% hint style="info" %}
In this command - we have only one Bot.sendMessage function!

It is good - code more simple.
{% endhint %}


# SRB Demo Keyboard Tools

demo bot by @SrbDev

> This is an Demo Example of Keyboard tools. You can use it for collecting user phone number and location by User click the buttons and you also can create big buttons

![](https://telegra.ph/file/06212eb820971e70d4179.png)Control Your Bot from Admin Panel

![](/files/-LwpW58TppsuXQLRpiE9)

![](/files/-LwpWESvc-12BLI-BnwB)

There is 2 option avialable on bb app Admin Panel of your bot. You can store data that you got from used by entering channel username on adminpanel and aslo you can change it at anytime you want from adminpanel. And Enter admin id on adminpanel that bot will send notification if any user enter any data

![](/files/-LwpWJPoe8RTU_UPtTJk)


