Перейти к содержанию

Вебхуки

Когда пользователь отправляет боту текст, геолокацию или контакт, BotFarm2 пересылает данные на текущую страницу пользователя POST-запросом.

Формат запроса

POST /your-page-url HTTP/1.1
Content-Type: application/json

{
  "text": "сообщение от пользователя",
  "location": null,
  "contact": null
}

Всегда присутствуют все три поля. Заполнено только одно из них — в зависимости от типа действия пользователя.

Типы событий

Текстовое сообщение

Пользователь отправил текст боту.

{
  "text": "Привет!",
  "location": null,
  "contact": null
}

Геолокация

Пользователь поделился местоположением.

{
  "text": null,
  "location": {
    "latitude": 55.7558,
    "longitude": 37.6173
  },
  "contact": null
}

Контакт

Пользователь поделился номером телефона (в ответ на .bf-request-contact).

{
  "text": null,
  "location": null,
  "contact": {
    "phone_number": "+79001234567",
    "first_name": "Иван",
    "last_name": "Иванов",
    "user_id": 123
  }
}
Поле Тип Описание
phone_number string Номер телефона в международном формате
first_name string Имя пользователя из мессенджера
last_name string Фамилия (может быть пустой)
user_id int ID пользователя в BotFarm (BFUser.id)

Файл

Пользователь отправил файл боту (Telegram).

POST /your-page-url HTTP/1.1
Content-Type: multipart/form-data

file: <бинарные данные файла>

Файлы отправляются как multipart/form-data, а не JSON.

Заголовки запроса

Каждый запрос к вашему бекенду содержит заголовки с информацией о пользователе:

Заголовок Описание
Botfarm-Hook-Secret Секретный токен компании — см. Проверка подлинности запросов
Botfarm-ID ID пользователя в BotFarm (BFUser.id)
Botfarm-User-ID Алиас для Botfarm-ID
Botfarm-First-Name Имя пользователя (URL-encoded)
Botfarm-Last-Name Фамилия (URL-encoded)
Botfarm-Username Username
Botfarm-Type Платформа: tg, vk, max, ig
Botfarm-Page Текущая страница пагинации кнопок
Botfarm-Tg-Ext-ID Telegram ID (если есть)
Botfarm-VK-Ext-ID VK ID (если есть)
Botfarm-Max-Ext-ID Max ID (если есть)
Botfarm-Avatar-URL URL аватара пользователя (если есть)

Проверка подлинности запросов

Заголовки Botfarm-ID, Botfarm-Tg-Ext-ID и остальные — это обычные HTTP-заголовки, их может подделать кто угодно, кто знает URL вашей страницы. Чтобы отличить настоящий запрос от BotFarm2 от подделки, используйте заголовок Botfarm-Hook-Secret.

В нём приходит секретный токен вашей компании (hook_secret_token). Вы получаете его:

  • в ответе на POST /createCompanyBot — поле hook_secret_token;
  • либо в админке BotFarm2 в карточке компании (поле «Секретный токен для хука»).

Токен один на компанию и одинаков для всех её ботов и страниц.

Заголовок отправляется при каждом обращении BotFarm2 к вашему бекенду:

  • GET-запросы за HTML страницы (навигация пользователя, /navigate, /refresh);
  • POST-запросы с текстом, геолокацией, контактом и файлами;
  • запросы на fallback_url бота;
  • запросы предпросмотра страницы из админки BotFarm2.

Проверяйте токен на каждом запросе

Без проверки любой, кто узнает URL страницы, сможет подставить чужой Botfarm-ID и получить или изменить данные другого пользователя.

Пример на Django

import secrets

from django.conf import settings
from django.http import HttpResponseForbidden


def check_botfarm_secret(request):
    """Возвращает True, если запрос действительно пришёл от BotFarm2."""
    received = request.META.get("HTTP_BOTFARM_HOOK_SECRET", "")
    return secrets.compare_digest(received, settings.BOTFARM_HOOK_SECRET)


def my_page(request):
    if not check_botfarm_secret(request):
        return HttpResponseForbidden("Invalid hook secret")
    ...

Сравнивайте токены через secrets.compare_digest (или аналог в вашем языке), а не через == — обычное сравнение строк уязвимо к timing-атакам. Сам токен храните в переменных окружения, а не в коде.

Пример на FastAPI

import os
import secrets

from fastapi import Header, HTTPException

BOTFARM_HOOK_SECRET = os.environ["BOTFARM_HOOK_SECRET"]


async def verify_botfarm_secret(botfarm_hook_secret: str = Header(default="")):
    if not secrets.compare_digest(botfarm_hook_secret, BOTFARM_HOOK_SECRET):
        raise HTTPException(status_code=403, detail="Invalid hook secret")

403 — особый статус

Если ваш бекенд вернёт 403, BotFarm2 считает, что пользователь заблокирован на вашей стороне, и молча пропускает запрос — пользователю ничего не отправляется и ошибка в сервисный чат не уходит. Это удобно для бана пользователей, но означает, что неверно настроенный секрет проявится как «бот молчит». Если хотите видеть проблему явно — возвращайте 400 или 500.

Пример обработки на Django

import json

def my_page(request):
    if request.method == "POST":
        # Файл
        if request.FILES:
            uploaded_file = request.FILES["file"]
            # Обработка файла...
            return render(request, "result.html")

        # JSON данные (текст, геолокация, контакт)
        data = json.loads(request.body)

        if text := data.get("text"):
            # Обработка текстового сообщения
            ...

        if location := data.get("location"):
            lat = location["latitude"]
            lon = location["longitude"]
            # Обработка геолокации
            ...

        if contact := data.get("contact"):
            phone = contact["phone_number"]
            user_id = contact["user_id"]
            # Обработка контакта
            ...

    # GET — обычный рендер страницы
    user_id = request.META.get("HTTP_BOTFARM_ID")
    bot_type = request.META.get("HTTP_BOTFARM_TYPE")
    return render(request, "my_page.html", {"user_id": user_id})

Ответ вашего бекенда

В ответ на POST-запрос бекенд должен вернуть HTML-страницу в том же формате, что и для GET-запросов. BotFarm2 распарсит HTML и отправит результат пользователю.

Обработка ошибок

Если ваш бекенд вернул HTTP-статус, отличный от 200:

  • 405, 401, 403 — если у бота настроен fallback_url, запрос перенаправляется туда
  • Другие ошибки — пользователю отправляется bot.error_message, уведомление в сервисный чат

Суперпользователи видят подробный traceback ошибки.

Запрос контакта

Чтобы запросить номер телефона пользователя, используйте класс .bf-request-contact в HTML:

<div class="bf-message bf-request-contact" data-button-text="Поделиться номером">
    <span class="bf-text">Для регистрации нам нужен ваш номер телефона</span>
</div>
Атрибут Обязательный Описание
class="bf-message bf-request-contact" Да Тип сообщения
data-button-text Нет Текст кнопки (по умолчанию: "Отправить номер телефона")

Пользователь увидит сообщение с кнопкой. При нажатии мессенджер запросит подтверждение, после чего BotFarm2 отправит POST-запрос с полем contact на текущую страницу.