For developers
Bots in Squeek
A bot is an account that a program answers for. It shows up in search, you can message it, and you can add it to a group or a channel. Here is how to create one from your phone and get it running in a few minutes.
Create a bot in the app
- Open “Profile” → “My bots”.
- Tap “Create bot”. Enter a name — this is how the bot appears in chats, for example
Weather— and a username: Latin letters only, and it must end withbot, for exampleweather_bot. - Tap “Create”. A dialog shows the token — a long string like
7:a91f…:3c0d…. Tap “Share” and send it to yourself (Saved messages, email, anywhere) or long-press to copy it.
The bot now exists: it appears in search as @weather_bot with a “bot” badge, you can message it, and you can add it to a group or a channel.
Run the bot on Node.js
The program that answers for the bot runs on your computer or server. You need Node.js and the squeek-bot library.
mkdir my-bot && cd my-bot && npm init -y && npm install squeek-botCreate bot.js:
const { SqueekBot } = require('squeek-bot');
const bot = new SqueekBot('7:a91f…:3c0d…'); // the token from the app
bot.on('message', async (msg) => {
console.log(msg.from.name, ':', msg.text);
if (msg.text === '/hi') await msg.reply('Hi! 🐀');
});
bot.on('connected', () => console.log('bot is online'));
bot.start();node bot.jsNow send /hi to the bot from the app — it replies.
message— an incoming message.msg.from.nameis the sender,msg.textis the text, andmsg.reply(text)answers in the same chat.connected— the bot has connected to the server.bot.start()— opens the connection and starts receiving messages.
Commands and description
Someone opening a chat with a bot for the first time has no idea what to type. So a bot has a description — the line under its name — and a command menu: it shows on the bot's profile and drops down in the composer as soon as you type «/». A chat with a bot opens with a **Start** button, which sends /start.
- In **My bots**, tap the pencil next to the bot.
- Write the description and the commands, one per line, as
/weather — forecast for tomorrow. - Save. The menu is there for everyone who opens a chat with it.
The program can do the same when it starts — handy when there are many commands, or when they change with the code:
bot.on('connected', async () => {
await bot.setDescription('Tells you the weather. Ask it with /weather.');
await bot.setCommands([
{ command: 'weather', description: 'Forecast for tomorrow' },
{ command: 'rain', description: 'Will it rain today' },
]);
});
bot.on('message', async (msg) => {
if (msg.text === '/start') await msg.reply('Hi! /weather tells you the forecast.');
});Edit, delete, react
A bot can rewrite its own message instead of sending a second one — «running → done» in one line. It can also delete its own message for everyone, and put an emoji on someone else's.
bot.on('message', async (msg) => {
if (msg.text !== '/backup') return;
await msg.react('👀');
const id = await bot.send(msg.chat.id, 'Backup: running…');
await makeBackup();
await bot.editMessage(msg.chat.id, id, 'Backup: done ✅');
});Send a message with a link
The simplest way to make the bot say something is a webhook: a link with a secret in it, and a single POST to it does the job. No sign-in, no token, no library — good for cron, a script, or anything that can call a URL.
- In “My bots”, tap the link icon next to the bot.
- Copy the link — it is shown once. It looks like
https://api.squeek.net/hooks/7/….
curl https://api.squeek.net/hooks/7/<secret> \
-H 'content-type: application/json' \
-d '{"text":"Backup finished"}'The message appears in your chat with the bot. To post to a channel instead, add ?chat=@channel_handle — the bot has to be an admin there:
curl 'https://api.squeek.net/hooks/7/<secret>?chat=@my_channel' \
-H 'content-type: application/json' \
-d '{"text":"A new version is on the site"}'Files
A bot can send a file to any chat it is in. The library takes care of the encryption.
const chart = await fs.promises.readFile('cpu.png');
await bot.sendFile(chatId, { name: 'cpu.png', data: chart, mimeType: 'image/png' }, 'Last hour');Posting later
Write now, publish whenever — a good-morning post at six, with nobody holding a phone. Channels only, including their discussions (the tabs of a channel). The queue is looked at every minute.
const id = await bot.schedule(chatId, 'Good morning 🐀', new Date('2026-10-01T06:00:00Z'));
await bot.scheduled(chatId); // what has not gone out yet
await bot.unschedule(id); // take it backA bot that keeps order
Make the bot an admin or a moderator of a group or channel and it can do what a person of that rank can: mute, ban, delete messages. With the same limits, too — it cannot touch anyone ranked above it.
bot.on('message', async (msg) => {
if (!looksLikeSpam(msg.text)) return;
await bot.deleteMessage(msg.id);
await bot.mute(msg.chat.id, msg.from.id, 60, 'spam');
});bot.mute(chatId, userId, minutes, reason?)— quiet for a while.bot.ban(chatId, userId, reason?)— out, for good.bot.unrestrict(chatId, userId)— lift a mute or a ban.bot.deleteMessage(messageId)— take a message down for everyone.
A bot without a server of its own
Hearing messages normally means a process running day and night. Without one, a bot can name a URL instead, and the server POSTs every message to it. The bot then lives anywhere that speaks HTTP: a free host, a function, a box at home.
const { url, secret } = await bot.setWebhook('https://my-bot.example/squeek');
// keep the secret — it signs every deliveryapp.post('/squeek', express.raw({ type: '*/*' }), async (req, res) => {
const msg = await bot.readWebhook(req.body.toString(), req.get('x-squeek-signature'), SECRET);
res.sendStatus(200); // answer first, work after
if (msg?.text === '/hi') await msg.reply('Hi there! 🐀');
});Post to a channel without the library
If the bot only posts to a channel, you do not need the library at all. Make the bot a channel admin and send two HTTP requests from any language. Private chats and groups do need the library.
The token has three colon-separated parts: botId:…:secret. Signing in takes the first (botId) and the third (secret).
curl https://api.squeek.net/auth/bot \
-H 'content-type: application/json' \
-d '{"botId":7,"secret":"3c0d…"}'The response contains accessToken. Then post to the channel, where chatId is the channel’s id:
curl https://api.squeek.net/messages \
-H "authorization: Bearer <accessToken>" \
-H 'content-type: application/json' \
-d '{"chatId":17,"content":"Hello, channel"}'A poll is the same request with a poll field:
curl https://api.squeek.net/messages \
-H "authorization: Bearer <accessToken>" \
-H 'content-type: application/json' \
-d '{"chatId":17,"content":"When do we meet?","poll":{"question":"When do we meet?","options":["Friday","Saturday"]}}'