SMeet Bot API
Quick start
Create a bot and get its first reply in a few minutes. You need a SMeet account with a confirmed e-mail and a computer with Python 3.9+ or Node.js 22.13+.
Before you start#
- Your account. Creating a bot needs a confirmed e-mail address. One person can own up to 5 bots.
- Permission in the space. A bot is created in the space where you open BotFather. In the public space the platform decides whether creation is open; in an organisation its administrators do (see Organisations and permissions). If creation is closed, BotFather says so.
- The examples. Download them for Python or Node.js. Each download unpacks into a folder
smeet-bot-exampleswith the bots, their README and a local mock server. Examples describes all of them.
Step 1. Create a bot#
- Open SMeet BotFather from My bots in the app, or open a chat with
@smeet_botfather. - Send
/newbotor press Create a bot. - Send the name people will see, 1 to 64 characters, for example
Support helper. - Send the address: 5 to 32 characters, lowercase Latin letters, digits and
_, starting with a letter and ending with_bot, for examplesupport_helper_bot.
BotFather answers: Done: @support_helper_bot is created. Status: not connected. If the address is taken, reserved or does not fit the rules, BotFather keeps the name and asks for another address.
Step 2. Get the token#
Press Get the token under BotFather's answer. It opens the protected token screen in your app; BotFather never posts the token into the chat.
The token looks like sbt1_<key id>_<secret> and is shown once. Copy it into a password manager or straight into the bot's .env file. SMeet keeps only a hash of it: if you lose it, issue a new one on the same screen, and the old one stops working at once.
Anyone with the token can act as your bot. Never put it into a URL, a chat, a screenshot or a git repository. Operations explains how to store and rotate it.
Step 3. Check the token#
getMe confirms that the token works and shows what SMeet knows about the bot. Put the token into the variable SMEET_BOT_TOKEN first; read -rs SMEET_BOT_TOKEN && export SMEET_BOT_TOKEN asks for it without echoing it and keeps it out of the shell history.
curl -s https://messenger.scrile.com/bot-api/v1/getMe \
-H "Authorization: Bearer $SMEET_BOT_TOKEN"{
"ok": true,
"result": {
"id": "5001",
"username": "support_helper_bot",
"display_name": "Support helper",
"is_bot": true,
"space": {"id": "1", "kind": "public", "name": "SMeet"},
"status": "active",
"delivery_mode": "polling",
"can_send_files": true
}
}id is the bot's account id: the messages your bot sends carry the same value as from.id. The token always travels in the Authorization header. A mistyped or revoked token gets 401 with the code INVALID_TOKEN. All identifiers are strings; keep them as strings in your code.
Step 4. Run the echo bot#
The echo bot answers /start and /help with a short text and sends any other text back. Both versions read SMEET_BOT_TOKEN and SMEET_API_URL from the environment or from a .env file in the current folder; SMEET_API_URL defaults to https://messenger.scrile.com/bot-api/v1.
Python#
unzip smeet-bot-examples-python.zip
cd smeet-bot-examples/python
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env # put the token into SMEET_BOT_TOKEN
python echo_bot.pyNode.js#
Node.js 22.13 or newer, no npm install: the examples use only what Node.js ships with.
unzip smeet-bot-examples-node.zip
cd smeet-bot-examples/node
cp .env.example .env # put the token into SMEET_BOT_TOKEN
node echo_bot.mjs # or: npm run echoThe program logs Running as @support_helper_bot, delivery mode polling and waits. This is the whole reply logic of the Python version; the key of every reply is built from the update's event_id, so a repeated update never produces a second message:
def handle(client: smeet.Client, update: dict) -> None:
# Only new messages matter here. Button presses, edits (an edit is a correction, not a new
# command), access changes and update types added in later API versions are ignored.
if update["type"] != "message":
return
message = update["message"]
client.send_message(
message["chat"]["id"],
reply_for(message),
# Same event, same key: a repeated update never produces a second reply.
idempotency_key=smeet.action_key(update["event_id"], "reply"),
)
log.info("Replied to update %s in chat %s", update["update_id"], message["chat"]["id"])Step 5. Press Start#
Open your bot in SMeet: search for its address or open https://messenger.scrile.com/u/support_helper_bot. Press Start.
The bot receives two updates: chat_access_changed with the status started, and your message /start. Within a second it answers:
Hello! Send me any text and I will send it back.
/help shows what I can do.Send any text and it comes back. Stop the program with Ctrl+C and start it again: it continues from where it stopped, because it keeps its position in echo_bot_state.json.
If nothing arrives, see If the bot is silent.
Try it without a token#
Both downloads have a local test double of the Bot API, mock-server/smeet_mock.py. It needs only Python and serves one bot with the token sbt1_mock_localtestonly; a control API under /_mock/ plays the user. Start each terminal in the folder where you unpacked the download:
# terminal 1: the mock
python3 smeet-bot-examples/mock-server/smeet_mock.py
# terminal 2: the bot
cd smeet-bot-examples/python
export SMEET_API_URL=http://127.0.0.1:8081/bot-api/v1
export SMEET_BOT_TOKEN=sbt1_mock_localtestonly
python echo_bot.py
# terminal 3: you, as the user
curl -s -X POST localhost:8081/_mock/start -d '{}' # the answer names the chat_id, here 550
curl -s -X POST localhost:8081/_mock/message -d '{"chat_id": "550", "text": "hello"}'
curl -s localhost:8081/_mock/chats/550The mock is not SMeet: it follows the contract closely enough to run every example, but it does not reproduce quotas, rate limits or the real server's durability. Check your bot against SMeet before you rely on it.
Step 6. Run it on a server#
A bot answers only while its program runs, so a laptop that sleeps is not enough. Long polling needs only outgoing HTTPS, so any server works, including one behind NAT. A systemd unit for the Python echo bot, with the smeet-bot-examples folder copied to /opt/smeet-bot:
[Unit]
Description=SMeet echo bot
After=network-online.target
Wants=network-online.target
[Service]
User=smeetbot
WorkingDirectory=/opt/smeet-bot/python
ExecStart=/opt/smeet-bot/python/.venv/bin/python echo_bot.py
Restart=on-failure
RestartSec=30
[Install]
WantedBy=multi-user.target- The
.envfile with the token stays in the working directory, readable only by the service user. The state fileecho_bot_state.jsonis written there too. - Run one copy per bot. A second copy gets
CONSUMER_CONFLICTand waits; that is how a standby copy works, not an error. systemctl stopsends SIGTERM, and the examples stop cleanly with exit code 0. On a configuration problem (a revoked token, webhook mode, a paused bot, bots switched off in the organisation) they log one line with the reason and exit with code 2; with this unit systemd tries again every 30 seconds until you fix it.- The echo bot is the learning example. For a bot that writes to a database, a CRM or a payment system, start from
python/production_poller.py: it stores every update before confirming it (Durable processing).
Next steps#
- Managing your bot: profile, commands, token, pause and deletion.
- Messages and buttons: buttons under messages, button presses, editing.
- Receiving updates: the delivery rules your program relies on.