Askora API.
Your bot from your site, CRM and Albato.

Message clients through your bot, update their variables and tags, run flow steps. Fetch clients and leads and get events at your own URL.

Key

The studio issues the key: open the bot, Integrations → Askora API → Issue key.

The key is shown once. If you lose it, replace it in the same place; the old one stops working. Each bot has its own key.

The key gives full access to the bot's clients: keep it on your server, not in website or app code.

Base URL

Base URL: https://botrun.atoms.technology/api/v1/…. A key from the studio knows which bot it belongs to, so the URL doesn't need the bot id.

If the key was set manually in the bot's Secrets (HOOK_KEY), use the URL with the bot id: https://botrun.atoms.technology/api/v1/bots/<BOT_ID>/…

Send every request with the header Authorization: Bearer <key>. The body is JSON, the response is JSON.

Set the client with one of two fields: client is the client number from Chats, chat is the Telegram chat id.

Methods

Times are Unix seconds everywhere.

GET/me

The bot: name, link, whether it is connected. Good for checking the key.

curl "https://botrun.atoms.technology/api/v1/me" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "bot": { "id": "<BOT_ID>", "name": "Студия Лак", "username": "lak_studio_bot", "link": "https://t.me/lak_studio_bot", "live": true, "paused": false } }

POST/messages

Message a client as the bot. The message appears in Chats.

client or chat
who to message
text
text, up to 4,096 characters
buttons
up to 10 link buttons: label up to 64 characters, url starting with https:// or tg://
curl -X POST "https://botrun.atoms.technology/api/v1/messages" \
  -H "Authorization: Bearer $CHATSY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client": 42, "text": "Your order is ready", "buttons": [{"label": "Pay", "url": "https://example.com/pay/318"}]}'
Response
{ "ok": true, "message_id": 1842 }

POST/clients/update

A client's variables, tags and stage. The bot doesn't message the client. A stage change sends the stage event.

client or chat
which client
vars
variables: string, number or true/false, up to 20 at once
tags
tags to add
untag
tags to remove
stage
a stage id from /stages (new, work, client, lost by default)
curl -X POST "https://botrun.atoms.technology/api/v1/clients/update" \
  -H "Authorization: Bearer $CHATSY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client": 42, "vars": {"paid": true, "order": "318"}, "tags": ["paid"], "stage": "client"}'
Response
{ "ok": true, "client": 42, "at": 1791200000, "sent": 0 }

POST/run

Run a bot step for a client: the bot sends that step and continues the flow.

client or chat
which client
step
a step id from /steps or its number on the flow (12 or №12)
vars
variables to set before the step, as in /clients/update
curl -X POST "https://botrun.atoms.technology/api/v1/run" \
  -H "Authorization: Bearer $CHATSY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"client": 42, "step": "12", "vars": {"order": "318"}}'
Response
{ "ok": true, "client": 42, "at": 1791200000, "sent": 1 }

GET/clients?since=&limit=&vars=1

Clients, newest first.

since
only clients who wrote after this time
limit
how many, 100 by default, up to 500
vars=1
with variables, then up to 100
curl "https://botrun.atoms.technology/api/v1/clients?limit=50&vars=1" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "clients": [
  { "client": 42, "chat": 123456789, "name": "Анна", "username": "anna", "stage": "new", "tags": ["vip"], "last_at": 1791200000,
    "vars": { "phone": "+79990000000" } }
] }

GET/clients/<client>

One client by the number from Chats, with variables.

curl "https://botrun.atoms.technology/api/v1/clients/42" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "client": { "client": 42, "chat": 123456789, "name": "Анна", "username": "anna", "stage": "new", "tags": ["vip"], "last_at": 1791200000,
  "vars": { "phone": "+79990000000" } } }

GET/clients/find?username=|phone=|var=&value=

Find a client. Searches the latest 500 clients, returns up to 20.

username
Telegram username, @ is optional
phone
a phone from the client's variables, the last 10 digits are compared
var and value
a variable and its value, case-insensitive
curl "https://botrun.atoms.technology/api/v1/clients/find?phone=%2B79990000000" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "clients": [{ "client": 42, "chat": 123456789, "name": "Анна", "username": "anna", "stage": "new", "tags": ["vip"], "last_at": 1791200000, "vars": { "phone": "+79990000000" } }] }

GET/stages

The bot's stages: ids for the stage field.

curl "https://botrun.atoms.technology/api/v1/stages" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "stages": [{ "id": "new", "name": "Новый" }, { "id": "work", "name": "В работе" }, { "id": "client", "name": "Клиент" }] }

GET/steps

The bot's steps: ids for the step field in /run. start marks the first step.

curl "https://botrun.atoms.technology/api/v1/steps" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "steps": [{ "id": "start", "title": "Здравствуйте! Я помогу записаться", "start": true }, { "id": "b12", "title": "Выберите услугу", "start": false }] }

GET/leads?since=&limit=

Leads, bookings and questions, newest first. For polling when you have no subscription.

since
only newer than this time
limit
how many, 50 by default, up to 500
curl "https://botrun.atoms.technology/api/v1/leads?since=1791100000" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "leads": [
  { "id": 318, "at": 1791200000, "kind": "lead", "title": "Заявка", "status": "new", "client": "Анна", "username": "anna",
    "what": "Маникюр, завтра", "details": [{ "q": "Услуга", "a": "Маникюр" }], "chat": 123456789 }
] }

GET/hooks

Event subscriptions.

curl "https://botrun.atoms.technology/api/v1/hooks" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "hooks": [{ "id": 7, "url": "https://example.com/askora", "events": ["lead", "message"], "createdAt": 1791200000 }] }

POST/hooks

Subscribe: events arrive as POST requests to your URL.

url
an https URL
events
which events, see the list below
curl -X POST "https://botrun.atoms.technology/api/v1/hooks" \
  -H "Authorization: Bearer $CHATSY_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/askora", "events": ["lead", "message"]}'
Response
{ "hook": { "id": 7, "url": "https://example.com/askora", "events": ["lead", "message"] } }

DELETE/hooks/<id>

Unsubscribe.

curl -X DELETE "https://botrun.atoms.technology/api/v1/hooks/7" \
  -H "Authorization: Bearer $CHATSY_KEY"
Response
{ "ok": true }

Errors

An error comes with an HTTP status and the body { "error": "code" }.

CodeHTTPWhat happened
api_off401the bot has no key: issue one in the studio
bad_key401the key is wrong, replaced or missing
not_found404no such bot, path or subscription
disconnected409the bot isn't connected to Telegram
no_client400client or chat is missing
no_query400/clients/find has nothing to search for
unknown_client404this client hasn't messaged the bot
bad_text400the text is empty or longer than 4,096 characters
bad_buttons400a button has no label or its url isn't https:// or tg://
no_step400step is missing in /run
bad_step400there's no such step on the flow
bad_var:<name>400the variable name is empty or too long
bad_value:<name>400the variable value isn't a string, number or true/false
bad_stage400the bot has no such stage
busy409the client is replying to the bot right now: retry the request
bad_url400the subscription URL isn't https
bad_events400the subscription has no known events
too_many409there are already 20 subscriptions: remove one
telegram502Telegram didn't accept the message, e.g. the client stopped the bot
rate_limited429more than 120 requests a minute: wait a little

Events

A subscription gets an event as soon as it happens. The body is JSON, the same as the bot's webhook.

  • lead a new lead or booking
  • question a client's question
  • client a new client messaged the bot
  • message a client's message
  • stage the client's stage changed
  • tags the client's tags changed
  • blocked the client stopped the bot

Every subscription event has chat_id, the client's chat, and client_number, their number in Dialogs: use either to reply right away via /messages. For message, data has kind (text, or press for a button tap) and text; for client, start; for stage, from and to; for tags, added and removed. lead and question have what and details (the client's questions and answers) instead of data. Examples, message and lead:

{
  "bot": { "id": "<BOT_ID>", "username": "lak_studio_bot", "name": "Студия Лак" },
  "event": {
    "kind": "message", "kind_label": "Сообщение клиента",
    "at": 1791200000, "at_iso": "2026-10-05T09:00:00.000Z",
    "chat_id": 123456789, "client_number": 12, "client": "Анна", "username": "anna",
    "data": { "kind": "text", "text": "Здравствуйте! Есть время на завтра?" }
  }
}
{
  "bot": { "id": "<BOT_ID>", "username": "lak_studio_bot", "name": "Студия Лак" },
  "event": {
    "kind": "lead", "kind_label": "Заявка",
    "at": 1791200000, "at_iso": "2026-10-05T09:00:00.000Z",
    "client": "Анна", "username": "anna", "chat_id": 123456789, "client_number": 12,
    "what": "Маникюр, завтра",
    "details": [{ "q": "Услуга", "a": "Маникюр" }, { "q": "Когда удобно", "a": "завтра" }]
  }
}

If the bot has a WEBHOOK_SECRET (Integrations → Webhook), every event comes with the header x-rilmo-signature: sha256=<HMAC-SHA256 of the body with that secret, in hex>.

Check the signature against the raw body, before parsing JSON:

import crypto from "node:crypto";

// raw - тело запроса как есть, до JSON.parse
const sig = "sha256=" + crypto.createHmac("sha256", process.env.WEBHOOK_SECRET).update(raw).digest("hex");
const ok = crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(req.headers["x-rilmo-signature"] ?? ""));

Limits

  • 120 requests a minute from one IP.
  • Message text up to 4,096 characters, up to 10 buttons.
  • Up to 20 subscriptions per bot.
  • Clients: up to 500 per request, up to 100 with variables. Leads: up to 500. Search: up to 20 among the latest 500 clients.

Make, n8n, Albato

Make and n8n: the HTTP module: the method URL, the header Authorization: Bearer <key>, a JSON body. For events, pass a Make or n8n webhook to POST /hooks.

Albato: the Askora app for the Albato catalog is in the works. Until then, use an HTTP request and an Albato webhook, as with Make.