FALCON BLACK English
Боты для Falcon Black
Бот — программа, которая отвечает людям в Falcon Black. Создаёте его в переписке с @botnest («Гнездо ботов»), берёте ключ на сайте и подключаете свою программу к Bot API: она получает сообщения людей и отвечает им. Форма API знакома тем, кто писал ботов для других платформ: те же имена методов и полей.
getUpdates) или вебхуком (setWebhook). Мини-приложения — ниже. Встроенный режим —
следующим шагом; на его вызовы сервер отвечает понятным отказом, а не молчанием.Быстрый старт
- Откройте в Falcon Black переписку с @botnest (найдите по нику) и напишите
/newbot. - Пришлите имя бота, потом ник — латиницей, на конце
bot(например,weather_kzn_bot). - Напишите
/token(или выберите бота в/mybots→ «Ключ через сайт») — Гнездо пришлёт одноразовый код на 10 минут. Ключ сообщением не приходит никогда. - Откройте falconblack.org/bots/key, введите код и пароль Falcon Black — ключ покажется
один раз. Сохраните его в переменную окружения
FB_BOT_TOKEN. - Запустите пример ниже и напишите своему боту: он ответит.
Адрес и ключ
Все методы: https://falconblack.org/bot-api/v1/<метод>, GET или POST
(JSON, форма или multipart/form-data для файлов). Ключ — только в заголовке:
Authorization: Bearer 1848831706977841:fb1_…
- Ключ в адресе запроса не принимается и сразу отключается (в строке запроса или в пути вида
/bot<ключ>/метод): адреса оседают в журналах прокси. Готовые библиотеки, которые кладут ключ в адрес, пока не подходят — пишите запросы сами (это 20 строк, см. примеры). - Ключ — как пароль. Мы его никогда не спрашиваем и не присылаем. Ключ, отправленный в любую переписку с
@botnest, отключается сам. Утёк —
/revokeили новый ключ в @botnest: прежний гаснет сразу. - В приложении ключ выпускается так же — «Мои боты» → бот → «Новый ключ», с паролем учётки — и тоже показывается один раз: сам ключ мы не храним, только его отпечаток. «Отозвать» там же.
- Вид ключа:
<номер бота>:fb1_<43 знака><сумма 6 знаков>. Сумма — CRC32 всего, что до неё, шестью знаками base62: опечатку видно до запроса.
import zlib from "node:zlib"; // Node 20.15+ / 22
const B62 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
export function keyLooksRight(key) {
const m = /^(\d{10,16}:fb1_[0-9A-Za-z]{43})([0-9A-Za-z]{6})$/.exec(key);
if (!m) return false;
let n = zlib.crc32(m[1]), sum = "";
for (let i = 0; i < 6; i++) { sum = B62[n % 62] + sum; n = Math.floor(n / 62); }
return sum === m[2];
}
Ответ 401 говорит, что с ключом: token_malformed — нет ключа или не та форма, token_checksum —
опечатка, token_unknown — такого ключа нет, token_revoked — ключ отозван
(parameters.revoke_reason: reissue, owner, leak_message,
leak_url, bot_deleted), key_in_url — ключ пришёл в адресе.
Пример: эхо-бот
Без библиотек, длинным опросом. Человек пишет — бот отвечает «Вы написали: …» и показывает кнопку «Бросить кубик»; человек отвечает «1» — бот бросает кубик. Проверено против сервера Falcon Black.
Node.js 20+ — echo.mjs
// Эхо-бот Falcon Black: Node.js 20+, без библиотек, длинный опрос.
// Запуск: FB_BOT_TOKEN='ключ со страницы falconblack.org/bots/key' node echo.mjs
// Ключ — только в переменной окружения и только в заголовке Authorization: Bearer
// (ключ в адресе запроса сервер сразу отключает).
const API = process.env.FB_API || "https://falconblack.org/bot-api/v1";
const HEADERS = { Authorization: `Bearer ${(process.env.FB_BOT_TOKEN || "").trim()}`, "Content-Type": "application/json" };
async function call(method, params = {}) {
const r = await fetch(`${API}/${method}`, { method: "POST", headers: HEADERS, body: JSON.stringify(params) });
let j;
try { j = await r.json(); } catch { throw new Error("ответ не JSON — сбой сети, повторим"); }
if (j.ok) return j.result;
throw Object.assign(new Error(j.description), { code: j.error_code, key: j.error_key, retryAfter: j.parameters?.retry_after });
}
// Кнопки люди пока видят списком с номерами под сообщением: ответ «1» приходит
// программе нажатием (callback_query). Ответ цифрой относится к ПОСЛЕДНЕМУ
// сообщению бота — поэтому кнопка есть под каждым ответом.
const DICE = { inline_keyboard: [[{ text: "Бросить кубик", callback_data: "roll" }]] };
async function handle(u) {
const m = u.message;
if (m?.text?.startsWith("/start")) {
// «/start» приходит первым, когда человек впервые написал боту.
await call("sendMessage", { chat_id: m.chat.id, text: "Здравствуйте! Напишите что-нибудь — я повторю.", reply_markup: DICE });
} else if (m?.text) {
await call("sendMessage", { chat_id: m.chat.id, text: `Вы написали: ${m.text}`, reply_markup: DICE });
} else if (u.callback_query?.data === "roll") {
const n = 1 + Math.floor(Math.random() * 6);
await call("answerCallbackQuery", { callback_query_id: u.callback_query.id });
await call("sendMessage", { chat_id: u.callback_query.message.chat.id, text: `Выпало ${n}`, reply_markup: DICE });
}
}
let offset = 0;
for (;;) {
let updates;
try {
updates = await call("getUpdates", { offset, timeout: 50 });
} catch (e) {
// 401 — ключ (причина — в e.key), 409 — запущена вторая копия: повтор не поможет.
if ([401, 403, 409].includes(e.code)) { console.error(`${e.code} ${e.key}: ${e.message}`); process.exit(1); }
await new Promise((ok) => setTimeout(ok, (e.retryAfter ?? 3) * 1000)); // сбой сети или 429
continue;
}
for (const u of updates) {
offset = u.update_id + 1;
// Ошибка одного события (человек заблокировал бота — 403, предел — 429) не роняет программу.
await handle(u).catch((e) => console.warn(`событие ${u.update_id}: ${e.code ?? ""} ${e.message}`));
}
}
Python 3.9+ — echo.py (нужен requests)
# Эхо-бот Falcon Black: Python 3.9+, только requests, длинный опрос.
# Запуск: FB_BOT_TOKEN='ключ со страницы falconblack.org/bots/key' python3 echo.py
# Ключ — только в переменной окружения и только в заголовке Authorization: Bearer
# (ключ в адресе запроса сервер сразу отключает).
import os, random, sys, time
import requests
API = os.environ.get("FB_API", "https://falconblack.org/bot-api/v1")
s = requests.Session()
s.headers["Authorization"] = "Bearer " + os.environ["FB_BOT_TOKEN"].strip()
class ApiError(Exception):
def __init__(self, j):
super().__init__(j.get("description"))
self.code, self.key = j.get("error_code"), j.get("error_key")
self.retry_after = (j.get("parameters") or {}).get("retry_after")
def call(method, **params):
try:
j = s.post(f"{API}/{method}", json=params, timeout=65).json()
except ValueError: # не JSON — страница прокси: временный сбой
raise ApiError({"description": "ответ не JSON — сбой сети, повторим"})
if not j.get("ok"):
raise ApiError(j)
return j["result"]
# Кнопки люди пока видят списком с номерами под сообщением: ответ «1» приходит
# программе нажатием (callback_query). Ответ цифрой относится к ПОСЛЕДНЕМУ
# сообщению бота — поэтому кнопка есть под каждым ответом.
DICE = {"inline_keyboard": [[{"text": "Бросить кубик", "callback_data": "roll"}]]}
def handle(u):
msg = u.get("message") or {}
text = msg.get("text") or ""
if text.startswith("/start"): # приходит первым, когда человек впервые написал боту
call("sendMessage", chat_id=msg["chat"]["id"], text="Здравствуйте! Напишите что-нибудь — я повторю.", reply_markup=DICE)
elif text:
call("sendMessage", chat_id=msg["chat"]["id"], text=f"Вы написали: {text}", reply_markup=DICE)
cq = u.get("callback_query")
if cq and cq.get("data") == "roll":
call("answerCallbackQuery", callback_query_id=cq["id"])
call("sendMessage", chat_id=cq["message"]["chat"]["id"], text=f"Выпало {random.randint(1, 6)}", reply_markup=DICE)
offset = 0
while True:
try:
updates = call("getUpdates", offset=offset, timeout=50)
except ApiError as e:
if e.code in (401, 403, 409): # ключ, бот отключён, вторая копия — повтор не поможет
sys.exit(f"{e.code} {e.key}: {e}")
time.sleep(e.retry_after or 3) # сбой сети или 429
continue
except requests.RequestException:
time.sleep(3)
continue
for u in updates:
offset = u["update_id"] + 1
try:
handle(u)
except (ApiError, requests.RequestException) as e: # 403 от заблокировавшего и т. п. не роняет программу
print(f"событие {u['update_id']}: {e}", file=sys.stderr)
Полные примеры — эхо фото и файлов, кнопки со счётчиком, меню команд на трёх языках, ключ повтора, разбор каждой ошибки: full.mjs (Node) и full.py (Python).
curl
curl -H "Authorization: Bearer $FB_BOT_TOKEN" https://falconblack.org/bot-api/v1/getMe
curl -H "Authorization: Bearer $FB_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"chat_id": 4815162342108, "text": "Привет!"}' \
https://falconblack.org/bot-api/v1/sendMessage
curl -H "Authorization: Bearer $FB_BOT_TOKEN" -F chat_id=4815162342108 -F caption="Отчёт" \
-F document=@отчёт.pdf https://falconblack.org/bot-api/v1/sendDocument
Профиль бота
То, что люди видят в профиле бота, в поиске и в пустой переписке: имя (до 64 знаков), картинка, «О боте» (до 120 знаков — в профиле и в поиске) и «Что умеет этот бот» (до 512 знаков — в пустой переписке, до «Начать»). Всё это меняется в @botnest и в приложении: «Мои боты» → бот → «Информация». Имя и тексты не должны выдавать бота за Falcon Black.
Команды
Команда — слово после «/», которое человек выбирает в меню бота: до 100 команд, каждая — от 1 до 32 знаков
(латиница, цифры и «_» или кириллица), описание — до 256 знаков. Меню задаётся в @botnest, в приложении («Мои боты» →
бот → «Команды») или программой: setMyCommands — в том числе для отдельного языка
(language_code) и для групп (scope).
Методы
Параметры — snake_case; числа можно строкой, булевы — true/false или "1"/"0";
reply_markup, commands, scope, allowed_updates — объектом или строкой JSON.
Незнакомые параметры пропускаются молча. chat_id — номер человека у вашего бота (он же номер переписки)
или отрицательный номер группы или канала (группы и каналы).
| Метод | Что делает |
|---|---|
getMe | Ваш бот: id, first_name, username; can_join_groups (можно ли добавлять в группы и каналы), can_read_all_group_messages (приватность выключена — так бот будет видеть в группах, куда его добавят теперь); falcon_trust (new / normal) и falcon_trust_until; has_main_web_app — у бота есть главное мини-приложение |
getUpdates | События: offset, limit (1–100), timeout (0–50 с), allowed_updates. Второй опрос вытесняет первый (тот получает 409) |
sendMessage | chat_id, text (до 4096 знаков UTF-16), parse_mode, reply_markup, reply_parameters (ответ на сообщение), disable_notification, protect_content (во всех send*: запрет пересылать и сохранять это сообщение — пересылку в другие переписки не пропускает сервер, в приложениях нет кнопок пересылки, копирования и сохранения; у сообщения — has_protected_content: true) |
sendPhoto | photo — файл загрузкой (multipart, до 10 МБ) или file_id; caption до 1024. Снимок пережимается, данные снимка (место съёмки) срезаются |
sendDocument | document — файл загрузкой (до 20 МБ) или file_id любого вида (фото, видео, голосовое уйдут файлом) |
sendVideo | video — MP4 или MOV загрузкой (до 20 МБ) или file_id видео; caption, duration, width, height. Формат проверяется по содержимому файла |
sendAudio | audio — MP3, M4A (AAC), WAV или FLAC (до 20 МБ) или file_id; title, performer, duration, caption. OGG пока нет — iPhone его не играет |
sendVoice | voice — голосовое M4A (AAC) или MP3 (до 20 МБ) или file_id; duration. OGG/Opus пока нет — отправьте sendDocument |
sendSticker | sticker — только из наших наборов: file_id стикера, который прислал человек, или из getStickerSet. Свой файл и адрес — нельзя, кнопок под стикером пока нет |
getStickerSet | name — короткое имя открытого набора (из ссылки на набор); стикеры с file_id для sendSticker |
sendLocation | latitude, longitude, horizontal_accuracy (0–1500 м). Живое место (live_period) — пока нет |
sendContact | phone_number, first_name, last_name; людям приходит текстом «имя, номер» (своего вида «контакт» в приложениях нет); vcard не учитывается |
setMessageReaction | Реакция бота на сообщение своей переписки: reaction — [{"type":"emoji","emoji":"👍"}], одна; пустой список — снять. Один эмодзи, в том числе флаг или клавиша с цифрой; у бота — одна реакция на сообщение. В канале — только реакции, которые разрешил владелец, и не больше разных на запись, чем задано (getChat: available_reactions, max_reaction_count). Пределы — как у правок |
editMessageText, editMessageReplyMarkup | Только свои сообщения; правка одних кнопок — без пометки «изменено» |
deleteMessage | Свои сообщения моложе 48 ч (сообщения человека в личной переписке — его, бот их не удаляет); свои записи канала — в любое время; чужие в группе или канале — с правом can_delete_messages |
answerCallbackQuery | Ответ на нажатие; show_alert: true с text — человек получит этот текст сообщением |
sendChatAction | typing — «печатает…» около 5 с |
setMyCommands, getMyCommands, deleteMyCommands | Меню команд: до 100, команда — латиница или кириллица (одна азбука), строчные, цифры, _, до 32 знаков; scope, language_code. Через API ничего не «исправляется»: /Всё — command_invalid |
getChat | Переписка с человеком: id, type: "private", first_name; группа или канал: type: "group" / "channel", title, has_protected_content (владелец запретил пересылать и сохранять), falcon_join_by_request (вход по любой ссылке — только по заявке) |
setWebhook, deleteWebhook, getWebhookInfo | Вебхук: события приходят POST-запросом на ваш адрес (ниже). url, secret_token, max_connections (до 10), allowed_updates, drop_pending_updates; пустой url — снять |
setChatMenuButton, getChatMenuButton | Кнопка у поля ввода: команды или мини-приложение (ниже) |
answerWebAppQuery | Ответ мини-приложения, открытого из переписки: одно сообщение бота (ниже) |
Вебхук
- Адрес — только
https, порт 443, 88 или 8443, имя, а не номер; безимя:пароль@. Внутренние адреса (локальные сети, сам сервер,localhost) иfalconblack.org— отказbad_webhook. Имя проверяется приsetWebhookи перед каждой отправкой; пробного запроса нет — вебхук можно ставить до запуска своего сервера. Свой сертификат (certificate) не принимается: нужен сертификат от общего удостоверяющего центра. - Запрос:
POST,Content-Type: application/json, тело — одинUpdate; заголовкиFalcon-Update-Idи, если заданsecret_token,X-Falcon-Bot-Api-Secret-Token. Имя заголовка отличается от других платформ: сверяйте его сами (три строки) или не передавайте секрет в готовую библиотеку. С какого адреса придут запросы, не обещаем — сверяйте секрет. - Успех — ответ 2xx за 10 с; тело ответа не читается, перенаправления не выполняются. Сбой связи — повтор через
5 с, 15 с, 30 с, 1, 2, 5, 10, 20, 40 минут и дальше раз в час; событие живёт сутки. Ответ 4xx/5xx на одно и то
же событие 5 раз подряд — событие выбрасывается (
falcon_dropped_today), очередь человека идёт дальше. - События одного человека — строго по порядку, разных людей — параллельно, до
max_connections. Новый адрес, пока ваша программа ни разу не ответила 2xx, получает одно событие не чаще раза в 5 секунд. - 15 минут без успеха —
falcon_state: "failing"вgetWebhookInfoи письмо от @botnest хозяину; вебхук сам не снимается.last_error_message— словами («Connection timed out», «Wrong response from the webhook: 502 Bad Gateway»…). - Пока стоит вебхук,
getUpdatesотвечает 409webhook_active. Новый ключ и отзыв ключа снимают вебхук — программа ставит его заново своим ключом.
// Node.js 20+: приёмник вебхука. Свой https-сервер или прокси перед ним (порт 443, 88 или 8443).
import http from "node:http";
const SECRET = process.env.FB_WEBHOOK_SECRET; // тот же, что в setWebhook
http.createServer((req, res) => {
// Сверяйте НАШ заголовок сами: готовые библиотеки ищут заголовок с другим именем.
if (req.headers["x-falcon-bot-api-secret-token"] !== SECRET) { res.writeHead(401).end(); return; }
let body = "";
req.on("data", (c) => (body += c));
req.on("end", () => {
const update = JSON.parse(body); // update_id — и в заголовке Falcon-Update-Id
res.writeHead(200).end(); // 2xx за 10 с — доставлено; работу — после ответа
handle(update);
});
}).listen(8080); // за прокси с https
// Один раз, при запуске программы:
// curl -H "Authorization: Bearer $FB_BOT_TOKEN" -d url=https://bot.example.org/hook \
// -d secret_token=$FB_WEBHOOK_SECRET https://falconblack.org/bot-api/v1/setWebhook
События
- Человек написал боту впервые — сначала
my_chat_member(left→member), потомmessage«/start» (если человек начал не с него), потом само сообщение. Знакомство по/startработает всегда. - Человек заблокировал бота —
my_chat_member(member→kicked); дальшеsendMessageотвечает 403 «bot was blocked by the user». Написал снова —kicked→member. message— текст (сentitiesbot_command, в том числе кириллических команд),photo,document,video,voice,audio,animation,location,sticker(егоfile_idгодится дляsendSticker); опросы и списки дел — без содержимого, с полемfalcon_type.- «Начать» по ссылке
falconblack.org/bot/<ник>?start=<параметр>— программа получаетmessageс текстом/start <параметр>(в переписке человек видит «/start»). callback_query— нажатие кнопки (см. ниже), с полемfalcon_via:digitилиlabel.- События групп и каналов (
channel_post,edited_message,chat_member…) — в разделе о группах.
{"update_id": 1, "my_chat_member": {"chat": {"id": 4815162342108, "type": "private", "first_name": "Маша"},
"from": {...}, "date": 1790000000,
"old_chat_member": {"status": "left", "user": {<бот>}}, "new_chat_member": {"status": "member", "user": {<бот>}}}}
{"update_id": 2, "message": {"message_id": 1, "text": "/start", "entities": [{"type": "bot_command", "offset": 0, "length": 6}], ...}}
{"update_id": 3, "message": {"message_id": 2, "date": 1790000000,
"chat": {"id": 4815162342108, "type": "private", "first_name": "Маша"},
"from": {"id": 4815162342108, "is_bot": false, "first_name": "Маша", "language_code": "ru"},
"text": "Привет"}}
Очередь событий хранится на сервере сутки и переживает его перезапуск; подтверждение — следующим
getUpdates с offset = последний update_id + 1. Удалённое человеком до выдачи
сообщение не отдаётся.
Кнопки
Новые приложения Falcon Black рисуют кнопки и клавиатуру-ответы сами. В старых сборках inline_keyboard
человек видит списком с номерами под текстом, а ответ цифрой (или надписью кнопки) приходит программе нажатием
callback_query:
Погода в Казани: +12, облачно.
1 — Обновить
2 — Завтра
3 — Карта: https://example.org/map
Ответьте цифрой.
- Ответ цифрой засчитывается, если это ответ на самое последнее сообщение бота с кнопками (или цитата на сообщение с кнопками) и ему меньше суток. Сообщение бота без кнопок отменяет ответ цифрой.
- Кнопка-ссылка (
url, толькоhttps) иcopy_text— человек получает адрес или текст сообщением бота. keyboard(клавиатура-ответы) — строка «Варианты ответа: …»; ответ приходит обычным текстом.remove_keyboardиforce_replyпринимаются.web_app— мини-приложение бота под сообщением или ячейкой клавиатуры, только в личной переписке (ниже).parse_mode(HTML,MarkdownV2,Markdown) принимается, разметка снимается: люди видят простой текст. Длина считается после снятия.
Что бот знает о человеке
- Номер человека — свой у каждого бота (два бота не сведут подписчиков по номеру), имя из профиля и язык приложения. Ника, телефона и фото бот не получает.
- Бот пишет только тем, кто сам ему написал и не заблокировал его. Способа написать человеку первым нет — и из группы тоже: участник группы, который не писал боту лично, получит от бота только сообщения в группе.
- Всё, что человек пишет боту, получает его автор — программа автора бота. Об этом человек видит строку в начале переписки.
Ссылки
- Никому и никогда: схема приложения
vortex:и служебные страницыfalconblack.org(можно только/@ники/bots, а также ссылки на бота и его мини-приложения/bot/<ник>[/<короткое имя>]с?start=или?startapp=— ровно в такой форме) — 400link_forbidden. - Ссылка на бота:
https://falconblack.org/bot/<ник>; с параметром для «Начать» —?start=<параметр>(до 64 знаковA-Z a-z 0-9 _ -, например метка приглашения). - Новый бот (первые 3 дня, до
falcon_trust_until) шлёт ссылки только своему хозяину; остальным — 403 «links are not allowed for new bots until …» (links_new_bot). Защита от одноразовых мошеннических ботов.
Ошибки
{"ok": true, "result": {...}}
{"ok": false, "error_code": 403, "description": "Forbidden: bot was blocked by the user",
"error_key": "blocked"}
{"ok": false, "error_code": 429, "description": "Too Many Requests: retry after 3",
"error_key": "too_many", "parameters": {"retry_after": 3}}
HTTP-код равен error_code; description — по-английски; error_key —
машинный код, его значения не меняются. В каждом ответе — заголовок X-Request-Id. Ответ не JSON — это
сбой сети, повторите запрос.
| Код | error_key | Когда |
|---|---|---|
| 400 | chat_not_found | Нет такого человека у этого бота |
| 400 | text_empty, too_long | Пустой текст; длиннее 4096 (подпись — 1024) |
| 400 | param_missing, param_invalid, bad_json | Нет параметра, не тот тип, сломанный JSON |
| 400 | param_unsupported, markup_unsupported | Пока не поддержано: файл по адресу, login_url… |
| 400 | content_protected, join_request_not_found | Файл по file_id из переписки, где запрещено пересылать и сохранять, — в другую переписку (бот там не начальник); заявки нет (уже рассмотрели или отменили) |
| 400 | webapp_not_registered, webapp_in_group, key_leak | Адрес кнопки web_app не ведёт на ваше мини-приложение; кнопка web_app в группе или канале; ключ бота в адресе (ключ отозван) |
| 400 | query_invalid, query_no_chat, text_reserved | answerWebAppQuery: запрос чужой, истёк или уже отвечен; приложение открыто не из переписки; текст кнопки меню выдаёт себя за Falcon Black |
| 400 | reply_not_found, edit_not_found, not_modified, delete_forbidden | Сообщение не найдено, не изменилось, удалить нельзя |
| 400 | file_invalid | Чужой или испорченный file_id |
| 400 | callback_expired | Нажатию больше 15 минут или чужой номер |
| 401 | token_*, key_in_url | Ключ (см. выше) |
| 403 | blocked, user_deleted | Человек заблокировал бота; удалил учётку |
| 403 | links_new_bot | Ссылка от нового бота не хозяину (в группе и канале — любая) |
| 403 | bot_kicked, not_member, cant_initiate, not_enough_rights | Бота убрали из группы или канала; бот вышел сам; человек из группы не писал боту лично; у бота нет нужного права |
| 400 | user_not_found, member_list_inaccessible, user_is_admin, private_chat | Бот не видел этого человека в группе; участники канала скрыты; начальника убрать нельзя; метод только для групп и каналов |
| 404 | method_unknown, method_unsupported | Опечатка в методе; метода пока нет (в описании — чем заменить) |
| 400 | bad_webhook, file_format | Адрес вебхука не подходит; файл не того формата (видео, звук, голосовое) |
| 409 | poll_replaced, webhook_active | Запущена вторая копия программы; getUpdates при вебхуке |
| 413 | file_too_big | Файл или тело больше предела |
| 422 | idempotency_mismatch | Тот же ключ повтора с другим телом |
| 429 | too_many | Предел; ждать parameters.retry_after секунд (и заголовок Retry-After) |
| 503 | not_configured | Боты на сервере временно выключены |
Ключ повтора: заголовок Idempotency-Key или параметр falcon_idempotency_key
(1–64 знака A-Z a-z 0-9 _ -) у всех send*.
Повтор с тем же ключом вернёт то же сообщение (заголовок Idempotent-Replayed: true), второго не будет.
Пределы
| Что | Новый бот (первые 3 дня) | Обычный |
|---|---|---|
Отправка (send*) всего | 10 в секунду, 300 в минуту | 30 в секунду, 1200 в минуту |
| Отправка в одну переписку | 1 в секунду, всплеск до 5 | |
| Правки и удаления в одну переписку | 3 в секунду | |
| Прочие вызовы | 30 в секунду | 50 в секунду |
| Текст / подпись | 4096 / 1024 знака (UTF-16, после снятия разметки) | |
| Файлы | фото 10 МБ, файл, видео, звук и голосовое — 20 МБ; JSON и форма — 128 КБ | |
| Вебхук | до 10 соединений; на один чужой сайт от всех ботов — 20 запросов разом и 30 в секунду | |
Опрос getUpdates | один на бота, timeout до 50 с; 30 вызовов в секунду | один на бота, timeout до 50 с; 50 вызовов в секунду |
Загрузка файлов (multipart) | не больше 2 одновременно на ключ | |
| Запросы с неверным ключом | 60 в минуту с адреса, дальше 429 на 10 минут | |
Отказ всегда явный — 429 с retry_after; молча в очередь ничего не ставится. Уведомления людям от
бота приходят как от обычного собеседника, но в одну переписку — не чаще раза в 10 секунд.
Если переносите бота с другой платформы
| Что | У нас |
|---|---|
| Ключ | Та же форма «номер:секрет», но только в заголовке Authorization: Bearer на /bot-api/v1/; в адресе — отключается |
| Где работают боты | Личная переписка, группы и каналы; в канале бот только начальник. Режим приватности в группе — каким был в момент добавления; бот-начальник получает все сообщения |
| Получение событий | getUpdates или вебхук; секрет — в заголовке X-Falcon-Bot-Api-Secret-Token |
| Номер человека | Свой у каждого бота; ника, фото и телефона нет |
| Первое сообщение | Программа сначала получает my_chat_member и /start; ссылка с параметром — falconblack.org/bot/<ник>?start=… |
| Кнопки | В новых приложениях — кнопки; в старых — список с номерами, нажатие — ответ цифрой (falcon_via) |
| Разметка текста | Принимается и снимается |
| Файлы | Загрузкой или file_id; по адресу — пока нет; getFile — пока нет; голосовые и звук в OGG — пока нет (M4A, MP3) |
| Контакт | Приходит людям текстом; стикеры — только из наших наборов |
| Удалить сообщение человека | В личной переписке — нельзя; в группе и канале — с правом can_delete_messages |
| Ссылки у нового бота | Первые 3 дня — только хозяину |
| Мини-приложения | Только зарегистрированные адреса, кнопки — в личной переписке, человек сначала разрешает; отличия ниже |
| Нет (404 с подсказкой) | Встроенный режим, платежи, игры, опросы, пересылка, живое место, sendAnimation, sendVideoNote, sendMediaGroup |
Группы и каналы
Бота добавляет начальник группы или канала — из профиля бота («Добавить в группу или канал») или по ссылке (ниже).
Автор бота может это запретить: /setjoingroups в @botnest или «Мои боты» в приложении; запрет не убирает
бота оттуда, где он уже есть. В группе бот — обычный участник (его видят все, и старые версии приложения), в канале
бот всегда начальник.
- Номер переписки — отрицательный
chat_id:{"id": -2251799813685, "type": "group", "title": "Семья"}(или"type": "channel"). У каждого бота свой номер одной и той же группы. Номер приходит вmy_chat_member, когда бота добавляют; убрали и добавили снова — номер тот же. - Писать —
sendMessageи другиеsend*с этимchat_id. Бота убрали — 403 «bot was kicked from the group chat»; вышел сам (leaveChat) — 403 «bot is not a member of the group chat». В группе, где писать могут только начальники, писать может бот-начальник. - В группе и канале — только кнопки под сообщением (
inline_keyboard): клавиатура-ответы,remove_keyboardиforce_reply— 400param_unsupported. Новый бот (первые 3 дня, доfalcon_trust_until) ссылок и кнопок-ссылок в группы и каналы не шлёт — 403links_new_bot. - Участник группы получает номер у вашего бота (
from.id), но лично бот ему не напишет, пока человек сам не написал боту: 403 «bot can't initiate conversation with a user». Этот номер годится дляgetChatMember,banChatMember,promoteChatMemberв той же группе.
{"update_id": 7, "my_chat_member": {"chat": {"id": -2251799813685, "type": "group", "title": "Семья"},
"from": {"id": 4815162342108, "is_bot": false, "first_name": "Маша"}, "date": 1790000000,
"old_chat_member": {"status": "left", "user": {<бот>}},
"new_chat_member": {"status": "member", "user": {<бот>}}}}
{"update_id": 8, "message": {"message_id": 41, "date": 1790000060,
"chat": {"id": -2251799813685, "type": "group", "title": "Семья"},
"from": {"id": 4815162342108, "is_bot": false, "first_name": "Маша"},
"text": "/weather@weather_kzn_bot", "entities": [{"type": "bot_command", "offset": 0, "length": 24}]}}
{"update_id": 9, "channel_post": {"message_id": 7, "date": 1790000120,
"chat": {"id": -3377699720527, "type": "channel", "title": "Новости района"},
"sender_chat": {"id": -3377699720527, "type": "channel", "title": "Новости района"}, "text": "Завтра ярмарка"}}
Что бот получает в группе: режим приватности
| Режим | Что приходит программе |
|---|---|
| Приватность включена (так у всех новых ботов) | /команда@ваш_бот; просто /команда — если из
ботов группы ваш последним писал в неё; ответы (цитаты) на сообщения бота; служебные события. Упоминание
@ника без команды и без ответа не приходит |
| Приватность выключена | Все сообщения группы |
| Бот — начальник группы | Все сообщения группы при любом режиме |
- Режим меняет автор:
/setprivacyв @botnest или «Мои боты». Он действует с момента добавления: в группах, где бот уже есть, ничего не меняется, пока бота не добавят заново.getMe→can_read_all_group_messagesпоказывает режим для новых групп. - Сообщения других ботов не приходят никогда.
- Участники видят, что бот получает: при добавлении в группе появляется строка «Бот @… добавлен в группу. Он видит только команды и ответы на свои сообщения.» или «…Он видит все сообщения группы — их получает автор бота.»; та же строка — когда бот стал или перестал видеть всё (его сделали начальником или сняли). В списке участников у бота подпись «видит все сообщения» или «не видит сообщения».
Каналы
- Бот получает каждую новую запись —
channel_post(сsender_chat, безfrom) — и её правку —edited_channel_post. Записи других ботов не приходят. - Публиковать —
sendMessageс номером канала и правомcan_post_messages(оно включено, когда бота добавляют в канал без выбора прав). Запись подписана каналом; кнопки-ссылки под ней рисуют новые приложения, в старых адреса видны текстом. - Свои записи бот правит и удаляет в любое время; чужие — с правами
can_edit_messagesиcan_delete_messages.
curl -H "Authorization: Bearer $FB_BOT_TOKEN" -H "Content-Type: application/json" \
-d '{"chat_id": -3377699720527, "text": "Свежий выпуск",
"reply_markup": {"inline_keyboard": [[{"text": "Читать", "url": "https://example.org/news/1"}]]}}' \
https://falconblack.org/bot-api/v1/sendMessage
Пример: новостной бот — сам публикует новости из ленты RSS или Atom по таймеру с кнопкой «Читать», правит свою
запись, если новость в ленте поменялась, удаляет старые; номер канала узнаёт из my_chat_member:
news.mjs (Node.js 20+) и news.py
(Python 3.9+ с requests).
Права бота-начальника
Те же имена, что в ChatAdministratorRights. В группе бот становится начальником, если ему дали хоть одно
право (или просто «сделать начальником»). Права проверяются при каждом вызове: начальник группы их поменял — действует
сразу, а программа получает my_chat_member с новыми правами.
| Право | Группа | Канал | Что разрешает |
|---|---|---|---|
can_change_info | да | да | setChatTitle, setChatDescription, setChatPhoto, deleteChatPhoto |
can_delete_messages | да | да | Удалять чужие сообщения (в канале — любые записи) |
can_restrict_members | да | — | banChatMember, unbanChatMember |
can_invite_users | да | да | exportChatInviteLink, createChatInviteLink, editChatInviteLink, revokeChatInviteLink, approveChatJoinRequest, declineChatJoinRequest |
can_pin_messages | да | — | pinChatMessage, unpinChatMessage, unpinAllChatMessages |
can_promote_members | да | да | promoteChatMember — с правами не больше своих |
is_anonymous | да | — | Сообщения бота подписаны группой |
can_post_messages | — | да | Публиковать записи |
can_edit_messages | — | да | Править чужие записи; закреплять |
setMyDefaultAdministratorRights (for_channels: true — для каналов) — какие права программа
просит по умолчанию: приложение отмечает их на листе прав, когда бота добавляют. getMyDefaultAdministratorRights
— прочитать.
Ссылки «добавить в группу» и «добавить в канал»
https://falconblack.org/bot/<ник>?startgroup=<параметр>— человек выбирает группу, где он начальник. Программа получаетmy_chat_member, а с параметром — ещёmessageс текстом/start@<ник> <параметр>от добавившего (в ленте группы его нет). Параметр необязателен: до 64 знаковA-Z a-z 0-9 _ -.https://falconblack.org/bot/<ник>?startchannel— то же для канала.&admin=— права через+:change_info,delete_messages,restrict_members,invite_users,pin_messages,promote_members,anonymous,post_messages,edit_messages;manage_chat— начальник без отдельных прав. Незнакомые и не подходящие к виду переписки — отбрасываются. Начальник видит отмеченные права и может их снять.- Свои ссылки автор видит в @botnest (
/mybots→ бот) и в «Мои боты».
События групп и каналов
my_chat_member— всегда: бота добавили (memberилиadministratorс правами), поменяли права, убрали (kicked), вышел сам (left), группу удалили.message,edited_message— по правилам приватности выше.channel_post,edited_channel_post— записи канала.callback_query— нажатие кнопки под сообщением бота любым участником группы.chat_member— кто вошёл, вышел, стал начальником — только боту-начальнику и только если он попросил:"chat_member"вallowed_updates(getUpdatesилиsetWebhook). Без этого не приходит. Вошедший по одобренной заявке — сvia_join_request: true.chat_join_request— человек подал заявку на вступление — только боту-начальнику с правомcan_invite_usersи только если он попросил:"chat_join_request"вallowed_updates. В событии —chat,from(номер человека у этого бота, имя, язык),dateиinvite_link— только если заявку подали по ссылке самого бота. Ника,user_chat_idи «о себе» нет: написать человеку бот может, только когда тот сам нажмёт «Начать».
Методы для групп и каналов
| Метод | Что делает |
|---|---|
getChat, getChatMemberCount | Название и вид; число людей (боты не считаются) |
getChatMember | Сам бот или человек, которого бот уже видел в этой переписке; в канале — только сам бот |
getChatAdministrators | В группе — начальники-люди и боты-начальники; в канале — только боты (начальники канала скрыты от подписчиков) |
leaveChat | Выйти самому |
pinChatMessage, unpinChatMessage, unpinAllChatMessages | С правом can_pin_messages (в канале — can_edit_messages) |
banChatMember, unbanChatMember, promoteChatMember | С правами can_restrict_members и can_promote_members |
setChatTitle, setChatDescription, setChatPhoto, deleteChatPhoto | С правом can_change_info |
exportChatInviteLink, createChatInviteLink, editChatInviteLink, revokeChatInviteLink | С правом can_invite_users. Бот работает только со своими ссылками.
exportChatInviteLink — своя главная ссылка бота (is_primary: true; прежняя отзывается; отозвали
главную — новая заводится сама). createChatInviteLink — с name (до 32 знаков, видно только
администраторам), expire_date, member_limit (1–99 999). editChatInviteLink —
меняет только присланные поля: expire_date: 0 снимает срок, member_limit: 0 — предел,
name: "" — название; главную ссылку не правят. Действующих дополнительных ссылок — до 30 на переписку.
creates_join_request: true — вход по ссылке только по заявке (вместе с member_limit нельзя; у
публичного канала — нельзя); в editChatInviteLink не передан — не меняется. У ссылки —
pending_join_request_count |
approveChatJoinRequest, declineChatJoinRequest | С правом can_invite_users: принять или отклонить заявку (chat_id, user_id — номер человека у бота из chat_join_request). Отклонённый сможет подать снова через сутки; заявки без ответа исчезают через 30 дней |
setMyCommands | Области для групп: all_group_chats, all_chat_administrators, chat и chat_administrators с номером группы |
Пределы в группах и каналах
| Что | Предел |
|---|---|
| Сообщений от бота в одну группу | 20 в минуту (вдобавок к 1 в секунду со всплеском до 5) |
| Сообщений от всех ботов одной группы | 60 в минуту |
| Записей от бота в один канал | 20 в минуту |
| Ботов в одной переписке | 10 в группе, 5 в канале |
| Событий в очереди бота | 10 000; сверх — первыми выбрасываются старые сообщения групп, my_chat_member — никогда |
Что видят участники
- Бот в списке участников — со значком «бот» и подписью «видит все сообщения» или «не видит сообщения».
- Строку о боте при добавлении и когда он стал или перестал видеть все сообщения.
- Уведомление от ответа бота в группе получает только тот, кому бот ответил или кого упомянул; остальным сообщение приходит тихо. Записи бота в канале — обычное уведомление подписчикам, но не чаще раза в 30 секунд.
- Кнопки под сообщением рисуют новые приложения; в старых — список с номерами, и в группе ответ цифрой засчитывается, только если это ответ (цитата) на сообщение бота.
- Записи бота в канале подписаны каналом.
Мини-приложения
Мини-приложение — ваш сайт, который открывается внутри Falcon Black: шторкой поверх переписки, на весь экран или во весь экран для игр. Человек открывает его из профиля бота, кнопкой под сообщением, кнопкой у поля ввода, ячейкой клавиатуры или по ссылке. При первом открытии он сам разрешает передать сайту своё имя и язык; ник, номер телефона, контакты и переписки сайт не получает. Сверху всегда видны название приложения и адрес сайта — их показывает Falcon Black, страница их не закрывает.
- В @botnest:
/newapp— бот → название → короткое имя (часть ссылки, потом не меняется) → адресhttps://→ описание → значок → адрес политики конфиденциальности → возраст. То же — в новых приложениях: «Мои боты» → «Мини-приложения». Список —/myapps, правка —/editapp(снимки для профиля, как открывать, другие адреса сайта), удалить —/deleteapp. - Адрес — только
https, порт 443, имя (не IP), сайт в открытом интернете. Адреса Falcon Black и местные адреса не подходят. Другие адреса сайта, куда приложение может переходить, — до 5 хостов (/editapp→ «Другие адреса сайта» или/setdomain). - Ссылка на приложение:
https://falconblack.org/bot/<ник бота>/<короткое имя>; с параметром —?startapp=<параметр>(до 512 знаковA-Z a-z 0-9 _ -, приходит вstart_param). Главное приложение бота —https://falconblack.org/bot/<ник>?startapp. Такие ссылки можно присылать и в сообщениях бота. - Первые 3 дня мини-приложения нового бота открываются только у его хозяина.
SDK
Подключите SDK в <head> страницы, до своего кода. Версионный файл не меняется никогда — поэтому
integrity; /sdk/mini-app.js — последний 1.x (без integrity).
<script src="https://falconblack.org/sdk/mini-app-1.0.0.js" integrity="sha384-iPxcV8KtBhjKcb6hdeKa5FnZRrlW+kJU+AYoR4BKChP9HgNjye3Giaz2muZbzZ8B" crossorigin="anonymous"></script>
Объект — window.FalconBlack.WebApp (то же — window.Falcon.WebApp). Методы возвращают обещание;
отказ — Error с name = "FalconWebAppError" и code (unsupported,
not_allowed, busy, cancelled, too_large, rate_limited).
Вне Falcon Black (в обычном браузере) initData пустая, а методы приложения отказывают
unsupported. SDK ничего не пишет ни в localStorage, ни в cookie.
| Что | Как |
|---|---|
| Готово, закрыть, развернуть | ready() — когда страница нарисована (до этого видна заглушка с вашим значком); close(); expand(); requestFullscreen() / exitFullscreen() |
| Главная кнопка | MainButton.setText("Оформить").show(), onClick(fn), enable() / disable(), showProgress() / hideProgress(), setParams({text, color, text_color, is_visible, is_active}) |
| Назад | BackButton.show() / hide(), onClick(fn) — вместо «Отмена» в шапке появляется «‹ Назад» |
| Окна | showPopup({title, message, buttons}) (до 3 кнопок), showAlert(text), showConfirm(text) — наши окна с названием и адресом вашего сайта в заголовке |
| Отклик | HapticFeedback.impactOccurred("light"), notificationOccurred("success"), selectionChanged() |
| Тема и размеры | themeParams, colorScheme, viewportHeight, viewportStableHeight, safeAreaInset, contentSafeAreaInset; CSS-переменные --fb-theme-bg-color, --fb-viewport-height, --fb-safe-area-inset-top…; события onEvent("themeChanged" | "viewportChanged" | …, fn) |
| Цвета | setHeaderColor, setBackgroundColor, setBottomBarColor (#rrggbb или ключ темы); enableClosingConfirmation() |
| Ссылки | openLink(url) — внешний сайт после подтверждения человеком; openFalconLink(url) — только /@ник, /bot/…, /j/… |
| Боту и в чат | sendData(строка) (ниже), shareToChat({text, startParam}) — человек сам выбирает переписку и отправляет сообщение от себя; приложение не узнаёт, кому; requestWriteAccess() — разрешить боту писать человеку |
| Проверка | isSupported("sendData"), isVersionAtLeast("1.0"), platform (ios, android, macos) |
Камеры, микрофона, места, контактов и номера телефона у мини-приложений в этой версии нет. Пример страницы — miniapp-example.html.
Как сервер приложения узнаёт человека: initData
WebApp.initData — строка формы (application/x-www-form-urlencoded). Отправьте её на свой
сервер в теле запроса (не в адресе: адреса оседают в журналах) и проверьте там. initDataUnsafe —
те же поля объектом, для показа на экране; решения по нему без проверки не принимайте.
auth_date=1767225600
chat_instance=4815162342
chat_type=private
falcon_app=shop
query_id=AgkQFx4lLDM6QUhPVl1ka3J5gIc
user={"id":4815162342,"is_bot":false,"first_name":"Анна","language_code":"ru","allows_write_to_pm":true}
signature=D0MD7q5YPfPXAYSUqYEeKQNaGELaM5L2wbT6VOW8Gf3OXTT-XY4vr9Dig8x4cpjIavTTdU6q_VQiSDwFZFsUDQ
hash=c1fc345d429647abd3ef6b19875af9b209fb854d9140b31c4ad0055fed761a1e
| Поле | Что |
|---|---|
user | JSON: id — номер человека у вашего бота (тот же, что в Bot API; у двух ботов — разный), first_name, language_code (если известен), allows_write_to_pm — бот может ему писать |
auth_date | Время открытия, секунды |
query_id | Номер открытия — для answerWebAppQuery |
chat_type, chat_instance | Только если открыто из переписки с ботом: private и номер переписки (как chat_instance у callback_query) |
start_param | Параметр из ссылки ?startapp= |
falcon_app | Короткое имя приложения |
signature, hash | Подпись Falcon Black и HMAC ключом бота (ниже) |
Ника, фото, номера телефона, настоящего id, контактов и названий переписок в initData нет никогда.
Строка проверки: все поля, кроме исключённых, по имени поля, каждое — имя=значение (значение
раскодировано: + — пробел), через \n. Разбирайте только декодером форм
(URLSearchParams, parse_qsl); поле дважды — строку отвергайте целиком.
- hash — HMAC ключом бота. Секрет =
HMAC_SHA256(key = "WebAppData", msg = <весь ключ бота>);hash = hex(HMAC_SHA256(key = секрет, msg = строка проверки без hash))— в строку входитsignature. Сравнивайте за постоянное время.hashесть, когда у живого ключа есть ключ приложений: ключ, выпущенный до мини-приложений, получает его при первом запросе к Bot API (или выпустите ключ заново). Новый ключ или отзыв — прежнийhashперестаёт сходиться. - signature — Ed25519 ключом Falcon Black, проверка без ключа бота: сообщение =
"<id бота>:WebAppData\n" + строка проверки без hash и signature;signature— base64url без=;id бота—getMe.id(левая часть ключа). Открытые ключи — /sdk/keys.json; пробуйте все (текущий и прежний — на время смены ключа). - Свежесть:
auth_dateне старше часа (жёсткий предел — сутки), допуск на часы — минута.
WebAppData — постоянная строка схемы, а не имя: готовые библиотеки проверки работают без правок.
Готовые проверки без библиотек: validate-initdata.mjs (Node.js 18+) и
validate-initdata.py (Python 3.9+, cryptography или
PyNaCl); векторы для своей реализации — initdata-vectors.json
(подписаны учебным ключом, на боевом его нет).
import { validateInitData, fetchPublicKeys } from "./validate-initdata.mjs";
const keys = await fetchPublicKeys(); // /sdk/keys.json: держите в памяти, обновляйте раз в час
// initData — из ТЕЛА запроса страницы, не из адреса
const r = validateInitData(initData, { botToken: process.env.FB_BOT_TOKEN, publicKeys: keys });
if (!r.ok) { res.writeHead(401).end(); return; }
const person = r.data.user; // {id, first_name, language_code?, allows_write_to_pm}
Кнопки web_app
{"chat_id": 4815162342108, "text": "Каталог открыт",
"reply_markup": {"inline_keyboard": [[{"text": "Открыть магазин", "web_app": {"url": "https://shop.example.com/item/5"}}]]}}
{"chat_id": 4815162342108, "text": "Что посмотрим?",
"reply_markup": {"keyboard": [[{"text": "Каталог", "web_app": {"url": "https://shop.example.com/catalog"}}, "Помощь"]],
"resize_keyboard": true}}
- Под сообщением (
inline_keyboard) и ячейкой клавиатуры (keyboard) — только в личной переписке:sendMessage, отправки с подписью,editMessageText,editMessageReplyMarkup. В группе и канале — 400webapp_in_group: дайте кнопкуurlсо ссылкойhttps://falconblack.org/bot/<ник>/<короткое имя>. - Адрес должен вести на ваше мини-приложение: хост — хост его адреса или один из других адресов сайта (подходят
несколько — то, чей адрес длиннейший общий префикс). Иначе 400
webapp_not_registered. Ключ бота в адресе — ключ отзывается, 400key_leak. Новый бот шлёт такие кнопки только хозяину. - Старые версии приложений: кнопку под сообщением показывают обычной кнопкой-ссылкой (сайт откроется в браузере, без входа через Falcon Black), а сборки без кнопок — строкой «1 — Открыть магазин: https://falconblack.org/bot/<ник>/<короткое имя> (открывается в новой версии Falcon Black)»; ответ цифрой — та же ссылка сообщением бота. Ячейка клавиатуры в старой версии отправляет свою надпись обычным текстом.
- Приложение скрыто, отключено или удалено — кнопка ведёт на ссылку-переход, сайт из неё не открывается.
Кнопка меню
setChatMenuButton — кнопка у поля ввода в переписке с ботом: вместо «/ Меню» новые приложения
показывают кнопку вашего мини-приложения (команды остаются в подсказках «/»). Без chat_id — для всех; с
номером человека — только в его переписке. Текст — 1–64 знака (выдаёт себя за Falcon Black — 400
text_reserved); адрес — по правилам кнопок web_app. getChatMenuButton
{chat_id?} — что задано. То же — /setmenubutton в @botnest и «Мои боты».
{"menu_button": {"type": "web_app", "text": "Магазин", "web_app": {"url": "https://shop.example.com/"}}}
{"chat_id": 4815162342108, "menu_button": {"type": "commands"}} // только в этой переписке
{"chat_id": 4815162342108, "menu_button": {"type": "default"}} // вернуть кнопку бота
Данные боту: sendData и web_app_data
Мини-приложение, открытое ячейкой клавиатуры, может один раз вызвать WebApp.sendData(строка)
(1–4096 байт UTF-8, не чаще 10 раз в минуту на человека): окно закрывается, а программа получает
message с полем web_app_data и без text — и опросом, и вебхуком
(в allowed_updates это message). В переписке ничего не появляется. Человек остановил бота —
данные не уходят.
{"update_id": 9, "message": {"message_id": 41, "date": 1790000000,
"chat": {"id": 4815162342108, "type": "private", "first_name": "Анна"},
"from": {"id": 4815162342108, "is_bot": false, "first_name": "Анна", "language_code": "ru"},
"web_app_data": {"data": "{\"item\":\"tea\"}", "button_text": "Каталог"}}}
answerWebAppQuery
Мини-приложению, открытому из переписки с ботом (кнопкой под сообщением, кнопкой меню или ячейкой клавиатуры), ваш
сервер может ответить один раз, пока открытие живо (час): человек получит одно обычное сообщение бота с
уведомлением, программа события о нём не получает. result — только статья с текстом
(input_message_content.message_text, parse_mode, кнопки inline_keyboard); текст и
кнопки — по всем правилам sendMessage. Ответ — {"falcon_message_id": N}.
{"web_app_query_id": "AgkQFx4lLDM6QUhPVl1ka3J5gIc",
"result": {"type": "article", "id": "1", "title": "Заказ",
"input_message_content": {"message_text": "Заказ №42 принят: чай, 250 ₽"},
"reply_markup": {"inline_keyboard": [[{"text": "Открыть заказ", "web_app": {"url": "https://shop.example.com/order/42"}}]]}}}
→ {"ok": true, "result": {"falcon_message_id": 57}}
Ошибки: 400 query_invalid — запрос чужой, истёк или уже отвечен; 400 query_no_chat —
приложение открыто не из переписки (из профиля, списка или по ссылке); 403 cant_initiate — человек не
запускал бота или остановил его: открытие мини-приложения не даёт боту права писать первым.
Чем отличается от других платформ
| Что | У нас |
|---|---|
answerWebAppQuery | Обычное сообщение бота в личной переписке; ответ {"falcon_message_id"}, inline_message_id нет |
Кнопки web_app | Только адреса зарегистрированного приложения и только в личной переписке |
| Встроенный режим | Нет (switch_inline_query, подготовленные сообщения — потом) |
| initData | Человек сначала разрешает; своё поле falcon_app; кроме hash — signature (Ed25519, без ключа бота); user.id — номер у вашего бота |
| Возможности страницы | Без камеры, микрофона, места, контактов, оплаты внутри; у каждой учётки — свои данные сайта |
Пределы
| Что | Предел |
|---|---|
| Мини-приложений у бота | 10; снимков для профиля — 5 (до 10 МБ каждый) |
| Открытий | 30 в минуту и 300 в час на человека |
sendData | один раз за открытие с клавиатуры, до 4096 байт, 10 в минуту на человека |
answerWebAppQuery | один раз за открытие, в течение часа |
| Свежесть initData | час (жёстко — сутки) |
Правила для авторов мини-приложений
- Не подражайте виду Falcon Black: шапку, окна и кнопки Falcon Black рисует сам, с названием и адресом вашего сайта.
- Никогда не спрашивайте пароль или код входа Falcon Black.
- Не продавайте цифровые товары и услуги пользователям iPhone (правило App Store 3.1.1); физические товары можно продавать через свою оплату на сайте.
- Политика конфиденциальности обязательна. Удаляйте данные человека по его просьбе.
- Возраст указывайте честно.
- На каждое приложение можно пожаловаться прямо в нём. Нарушит правила — приложение отключим; повторится — бота тоже.
Правила для авторов ботов
- Бот не выдаёт себя за Falcon Black, за другого человека или организацию.
- Бот не рассылает рекламу и не пишет тем, кто не просил.
- Бот не выманивает пароли, коды входа, данные карт и деньги обманом.
- Всё, что люди пишут боту, — чужое. Храните бережно, никому не показывайте и удаляйте по просьбе человека.
- Ключ — как пароль. Мы его никогда не спрашиваем.
- За бота отвечает его хозяин. Нарушит правила — бота отключим; повторится — создавать ботов будет нельзя.
Полностью — falconblack.org/bots/rules.
Политика конфиденциальности бота: адрес — «Мои боты» → бот → «Настройки бота»; без него действует стандартная политика Falcon Black для ботов.
Чего пока нет
Встроенный режим, передача бота другому хозяину, скачивание файлов
(getFile), отправка файла по адресу, живое место, обсуждения под записями канала. На эти вызовы — понятный
отказ. Управлять ботом можно в @botnest и в новых приложениях: «Мои боты» — имя, описание, картинка, команды, ключ,
группы и приватность, мини-приложения. Вопросы и пожелания — в @botnest: /help.