Перейти к содержимому

Шаг 4. Уведомления на свой сервер

Обновлено 17 октября 2026

В этом шаге Gratio начнёт присылать уведомления на ваш адрес сам — опрашивать очередь не нужно.

Что понадобится

  • переменные GRATIO_URL, GRATIO_ID, GRATIO_TOKEN из Шаг 2. Первый запрос;
  • Python 3.10+ (pip install fastapi uvicorn) или Node.js 18+ (npm install express);
  • публичный HTTPS-адрес, который ведёт на ваш обработчик. На своём компьютере подойдёт любой сервис туннелей, который выдаёт публичный HTTPS-адрес для локального порта.

Как работает вебхук

Gratio                                   Ваш сервер
   │ POST /gratio/hook  {уведомление} ──────►│ проверить токен
   │                                         │ сохранить, ответить сразу
   │◄──────────────────────────── 200 OK ────│
   │                                         │ обработать в фоне
   │ POST /gratio/hook  {следующее} ────────►│
   │                                         │
   │  нет ответа или не 2xx:                 │
   │  повтор через 1, 5, 15, 60, 300 с …     │

1. Запустите обработчик

Придумайте секрет — длинную случайную строку — и сохраните в GRATIO_HOOK_TOKEN. Gratio будет присылать его в заголовке Authorization.

Python

Файл hook.py, запуск — uvicorn hook:app --port 8080:

import os
from fastapi import BackgroundTasks, FastAPI, Header, HTTPException

app = FastAPI()
HOOK_TOKEN = os.environ["GRATIO_HOOK_TOKEN"]


def process(body: dict) -> None:
    print(body["typeWebhook"], body.get("senderData", {}).get("chatId"), body.get("messageData"))


@app.post("/gratio/hook")
async def hook(body: dict, tasks: BackgroundTasks, authorization: str = Header("")):
    if authorization != f"Bearer {HOOK_TOKEN}":
        raise HTTPException(status_code=401)
    tasks.add_task(process, body)
    return {"ok": True}

Node.js

Файл hook.mjs, запуск — node hook.mjs:

import express from "express";

const app = express();
app.use(express.json({ limit: "1mb" }));

app.post("/gratio/hook", (req, res) => {
  if (req.get("authorization") !== `Bearer ${process.env.GRATIO_HOOK_TOKEN}`) {
    return res.sendStatus(401);
  }
  res.sendStatus(200);
  const body = req.body;
  console.log(body.typeWebhook, body.senderData?.chatId, body.messageData);
});

app.listen(8080);

Вы увидите: сервер слушает порт 8080.

2. Откройте публичный адрес

Направьте туннель на порт 8080 или разместите обработчик на сервере с HTTPS. Адрес обработчика — например, https://example.ru/gratio/hook.

Адрес должен быть публичным: внутренние и локальные адреса Gratio не принимает (400 bad_url).

3. Укажите адрес в настройках канала

Метод setSettings: адрес вебхука и ваш секрет. Замените адрес и секрет на свои:

curl

curl -X POST "$GRATIO_URL/waInstance$GRATIO_ID/setSettings/$GRATIO_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "webhookUrl": "https://example.ru/gratio/hook",
    "webhookUrlToken": "s3cr3t-hook-token"
  }'

Python

import os
import requests

BASE = f"{os.environ['GRATIO_URL']}/waInstance{os.environ['GRATIO_ID']}"
TOKEN = os.environ["GRATIO_TOKEN"]

url = f"{BASE}/setSettings/{TOKEN}"
payload = {
    "webhookUrl": "https://example.ru/gratio/hook",
    "webhookUrlToken": "s3cr3t-hook-token",
}
response = requests.post(url, json=payload, timeout=60)
print(response.status_code, response.json())

Node.js

const { GRATIO_URL, GRATIO_ID, GRATIO_TOKEN } = process.env;
const base = `${GRATIO_URL}/waInstance${GRATIO_ID}`;

const url = `${base}/setSettings/${GRATIO_TOKEN}`;
const payload = {
  webhookUrl: "https://example.ru/gratio/hook",
  webhookUrlToken: "s3cr3t-hook-token",
};
const response = await fetch(url, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify(payload),
});
console.log(response.status, await response.json());

PHP

<?php
$base = getenv('GRATIO_URL') . '/waInstance' . getenv('GRATIO_ID');
$url = $base . '/setSettings/' . getenv('GRATIO_TOKEN');
$payload = [
    'webhookUrl' => 'https://example.ru/gratio/hook',
    'webhookUrlToken' => 's3cr3t-hook-token',
];

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_POSTFIELDS => json_encode($payload, JSON_UNESCAPED_UNICODE),
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 60,
]);
$response = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), PHP_EOL;
print_r($response);

Вы увидите: {"saveSettings": true}.

4. Проверьте

Напишите на подключённый номер с телефона.

Вы увидите в консоли обработчика:

incomingMessageReceived 8695836 {'typeMessage': 'textMessage', 'textMessageData': {'textMessage': 'Здравствуйте!'}}

Пока задан вебхук, receiveNotification отвечает 400 webhook_set — у канала одна очередь, и её читает вебхук. Вернуться к очереди — setSettings с "webhookUrl": "".

Правила для обработчика

  • Отвечайте сразу, обработку делайте в фоне: Gratio ждёт ответа 30 секунд.
  • Проверяйте секрет в Authorization.
  • Отсекайте повторы по eventId: если ответ потерялся, уведомление придёт снова.
  • Не обрабатываете уведомление — всё равно ответьте 200, иначе очередь встанет на нём.

Подробно — в статье Вебхук.

Что дальше

Канал подключён, сообщения уходят и приходят. Выберите сценарий:

Чат-бот на PythonБот, который отвечает клиентам в MAX, Telegram или WhatsApp по меню, присылает файл и зовёт оператора, — на очереди уведомлений, без публичного сервера. Переписка в своей CRMВстроить чаты MAX, Telegram и WhatsApp в свою CRM — входящие в карточку, ответ оператора, статусы, сообщения с телефона, правки, история и разрыв истории. Напоминания и рассылки без блокировокСкрипт напоминаний клиентам — выбор канала по номеру, рабочие часы, темп, правила WhatsApp, отложенные повторы и защита от дублей.

Или изучите основы: Как проходят сообщения и уведомления, Темп и лимиты, Ответы и ошибки.

Была ли статья полезна?