Войти

Вебхуки

Вебхук присылает POST-запрос на ваш сервер о каждом новом посте выбранных каналов MAX — обычно через 1–2 минуты после того, как мы его прочитали. Опрашивать ленту каждые несколько минут не нужно.

К сведению

Вебхуки открыты с тарифа «API.Max Рост»: 1 вебхук и до 500 каналов. «API.Max Профи» — 5 вебхуков и до 5 000 каналов на каждый. Управление вебхуками не расходует запросы.

Ключ «чтение и запись»

Создавать и менять вебхуки может только ключ с отметкой «чтение и запись». Её ставят при создании ключа на странице «API-ключи» в кабинете, потом она не меняется. Ключ без отметки получит ответ 403 с кодом read_only_key.

Создайте вебхук

# создать вебхук: адрес вашего сервера и номера каналов datool.ru
# нужен ключ с отметкой «чтение и запись»; в ответе — секрет подписи (один раз)
curl -X POST https://api.datool.ru/v1/max/webhooks/ \
  -H "Authorization: Bearer dtk_ваш_ключ" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://example.com/hooks/datool", "channels": [4821, 5310]}'
  • url — адрес https:// вашего сервера (адреса внутренних сетей и localhost не подходят);
  • channels — номера открытых каналов MAX в datool.ru (поле id в каталоге и карточке канала).

В ответе — поле secret. Сохраните его: он показывается один раз, им подписано каждое событие. Новый секрет — POST /v1/max/webhooks/{id}/rotate-secret/.

Проверить адрес: POST /v1/max/webhooks/{id}/test/ пришлёт событие ping без постов — одна попытка без повторов, не чаще раза в минуту на вебхук (чаще — 429 throttled). Итог — в полях last_success_at и last_error.

Создавать, менять и удалять вебхуки может ключ «чтение и запись» владельца или администратора организации; ключ обычного участника получит 403 manager_required. Адрес может быть и на кириллическом домене (.рф).

Что приходит

{
  "event": "post.created",
  "webhook": 12,
  "created_at": "2026-10-18T12:00:00+03:00",
  "posts": [
    {
      "id": 9876543,
      "channel": 4821,
      "text": "Мэрия открыла новый парк на набережной…",
      "views": 18450
    }
  ]
}
Поле Что в нём
event post.created — новые посты, ping — пробная доставка
webhook Номер вебхука
created_at Когда событие собрано (ISO 8601, по Москве)
posts Посты — у ping пустой список

В posts — до 100 постов, каждый в том же виде, что отдаёт GET /v1/max/posts/{id}/. Присылаем только свежие посты (опубликованные не раньше чем за двое суток); правки и удаление постов пока не присылаем.

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

Заголовок Что в нём
X-Datool-Event post.created или ping
X-Datool-Delivery номер доставки; при повторе тот же
X-Datool-Signature t=<время>,v1=<подпись>

Проверьте подпись

Подпись — HMAC-SHA256 строки <t>.<тело запроса> вашим секретом. Сверяйте её до разбора JSON и отклоняйте события старше 5 минут — так чужой не подделает событие и не повторит старое.

import hashlib
import hmac
import time


def is_valid(secret: str, body: bytes, header: str) -> bool:
    """Проверить подпись события: secret — секрет вебхука, body — сырое тело запроса."""
    # заголовок X-Datool-Signature: «t=<время>,v1=<подпись>»
    try:
        parts = dict(item.split("=", 1) for item in header.split(","))
        timestamp = int(parts["t"])
        signature = parts["v1"]
    except (ValueError, KeyError):
        # заголовка нет или он испорчен — событие не от datool.ru
        return False
    # событие старше 5 минут — отклоняем: так старое событие не повторить
    if abs(time.time() - timestamp) > 300:
        return False
    # подпись — HMAC-SHA256 строки «<t>.<тело>» вашим секретом
    expected = hmac.new(
        secret.encode(), f"{timestamp}.".encode() + body, hashlib.sha256
    ).hexdigest()
    # сравнение за постоянное время — по времени ответа подпись не подобрать
    return hmac.compare_digest(expected, signature)

Пример приёмника

# приёмник событий на Flask: pip install flask
from flask import Flask, abort, request

app = Flask(__name__)
# секрет из ответа на создание вебхука (храните в настройках, не в коде)
SECRET = "whsec_…"


@app.post("/hooks/datool")
def datool_hook():
    # сырое тело — подпись считается по нему, до разбора JSON
    body = request.get_data()
    if not is_valid(SECRET, body, request.headers.get("X-Datool-Signature", "")):
        # подпись не сошлась — событие не от datool.ru
        abort(401)
    event = request.get_json()
    if event["event"] == "post.created":
        for post in event["posts"]:
            # сохраните пост у себя; одно событие может прийти дважды — сверяйте post["id"]
            print(post["id"], post["text"][:80])
    # отвечаем 2xx быстро, тяжёлую обработку — после ответа
    return "", 204

Ответ и повторы

Ответьте кодом 2xx за 10 секунд — тяжёлую обработку делайте после ответа. Переадресации мы не выполняем.

Если ответа нет или код другой, повторяем через 1, 5, 15 минут, 1, 3, 6 и 12 часов — последняя попытка примерно через 22 часа. Событие, которое не прошло за сутки, не доставляется. Тело вашего ответа мы не читаем — важен только код. Одно событие может прийти дважды — отличайте посты по id.

Если за сутки не прошло ни одной доставки, вебхук выключается, а владельцам и администраторам организации приходит письмо. Почините сервер и включите вебхук: PATCH /v1/max/webhooks/{id}/ с {"is_active": true} или кнопкой «Включить» на странице «API-ключи». Посты пойдут с момента включения. Вебхук, выключенный сотрудником datool.ru (disabled_reason: staff), так не включить — ответ 409 conflict; напишите в поддержку.

Если тариф закончился

Вебхуки не удаляются, но события перестают приходить. После продления — снова приходят, с текущего момента.

Все методы — в справочнике (группа «MAX: вебхуки»).

Страница полезна?

Вы покидаете datool.ru

Ссылка ведёт на внешний сайт. datool.ru не отвечает за его содержимое — проверьте адрес, прежде чем вводить пароли или платёжные данные.

Переход через 10 с

Перейти