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

Шаг 3. Примите входящие

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

В этом шаге вы примете сообщение из очереди уведомлений канала и ответите на него. Очередь работает без публичного адреса у приложения — подойдёт ноутбук.

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

  • переменные GRATIO_URL, GRATIO_ID, GRATIO_TOKEN из Шаг 2. Первый запрос;
  • телефон, с которого вы напишете на подключённый номер.

Как работает очередь

Приложение                         Gratio
    │ receiveNotification ────────────►│  ждёт до receiveTimeout секунд
    │◄──────── {receiptId, body} ──────│  самое старое неподтверждённое
    │                                  │
    │ обработать body                  │
    │                                  │
    │ deleteNotification/{receiptId} ─►│  подтвердить
    │◄──────── {"result": true} ───────│
    │                                  │
    │ receiveNotification ────────────►│  следующее…

Пока уведомление не удалено, оно приходит снова — даже после перезапуска приложения. Так ничего не теряется.

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

С личного телефона отправьте на номер канала: «Здравствуйте!».

2. Заберите уведомление

receiveTimeout — сколько секунд ждать, если очередь пуста (до 60):

curl

curl "$GRATIO_URL/waInstance$GRATIO_ID/receiveNotification/$GRATIO_TOKEN?receiveTimeout=20"

Python

import os
import requests

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

url = f"{BASE}/receiveNotification/{TOKEN}"
params = {"receiveTimeout": "20"}
response = requests.get(url, params=params, timeout=90)
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 query = new URLSearchParams({ receiveTimeout: "20" });
const url = `${base}/receiveNotification/${GRATIO_TOKEN}?${query}`;
const response = await fetch(url);
console.log(response.status, await response.json());

PHP

<?php
$base = getenv('GRATIO_URL') . '/waInstance' . getenv('GRATIO_ID');
$url = $base . '/receiveNotification/' . getenv('GRATIO_TOKEN');
$url .= '?' . http_build_query(['receiveTimeout' => '20']);

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_TIMEOUT => 90,
]);
$response = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), PHP_EOL;
print_r($response);

Вы увидите:

{
  "receiptId": 1,
  "body": {
    "typeWebhook": "incomingMessageReceived",
    "instanceData": {"idInstance": 7100000001, "wid": "79990000001@c.us", "typeInstance": "v3", "channel": "max"},
    "timestamp": 1791823658,
    "idMessage": "117428955282341903",
    "eventId": "msg:8695836:117428955282341903",
    "senderData": {
      "chatId": "8695836", "chatName": "Мария", "chatType": "user",
      "sender": "8695836", "senderName": "Мария", "senderType": "user",
      "senderContactName": "", "senderPhoneNumber": 0
    },
    "messageData": {"typeMessage": "textMessage", "textMessageData": {"textMessage": "Здравствуйте!"}}
  }
}

receiptId — номер в очереди, body — само уведомление. senderData.chatId — куда отвечать. Пустая очередь — ответ null: напишите ещё раз и повторите запрос.

3. Подтвердите уведомление

Передайте receiptId в конце пути:

curl

curl -X DELETE "$GRATIO_URL/waInstance$GRATIO_ID/deleteNotification/$GRATIO_TOKEN/1"

Python

import os
import requests

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

url = f"{BASE}/deleteNotification/{TOKEN}/1"
response = requests.delete(url, 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}/deleteNotification/${GRATIO_TOKEN}/1`;
const response = await fetch(url, { method: "DELETE" });
console.log(response.status, await response.json());

PHP

<?php
$base = getenv('GRATIO_URL') . '/waInstance' . getenv('GRATIO_ID');
$url = $base . '/deleteNotification/' . getenv('GRATIO_TOKEN') . '/1';

$ch = curl_init($url);
curl_setopt_array($ch, [
    CURLOPT_CUSTOMREQUEST => 'DELETE',
    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);

Вы увидите: {"result": true}. Следующий receiveNotification отдаст уже другое уведомление.

4. Ответьте

chatId — из senderData.chatId пришедшего сообщения:

curl

curl -X POST "$GRATIO_URL/waInstance$GRATIO_ID/sendMessage/$GRATIO_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "chatId": "8695836",
    "message": "Здравствуйте! Чем помочь?"
  }'

Python

import os
import requests

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

url = f"{BASE}/sendMessage/{TOKEN}"
payload = {"chatId": "8695836", "message": "Здравствуйте! Чем помочь?"}
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}/sendMessage/${GRATIO_TOKEN}`;
const payload = { chatId: "8695836", message: "Здравствуйте! Чем помочь?" };
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 . '/sendMessage/' . getenv('GRATIO_TOKEN');
$payload = ['chatId' => '8695836', 'message' => 'Здравствуйте! Чем помочь?'];

$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);

Вы увидите ответ на телефоне. В очередь придут ещё два уведомления о вашем сообщении: outgoingAPIMessageReceived и outgoingMessageStatus со статусом sent, — их тоже нужно забрать и удалить.

Готовый цикл

Цикл забирает уведомления, отвечает на текст и подтверждает каждое уведомление.

Python

import os
import requests

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


def handle(body: dict) -> None:
    if body["typeWebhook"] != "incomingMessageReceived":
        return
    data = body["messageData"]
    if data["typeMessage"] != "textMessage":
        return
    text = data["textMessageData"]["textMessage"]
    requests.post(f"{BASE}/sendMessage/{TOKEN}", timeout=60, json={
        "chatId": body["senderData"]["chatId"],
        "message": f"Получили: {text}",
        "clientMessageId": f"echo-{body['idMessage']}",
    })


while True:
    url = f"{BASE}/receiveNotification/{TOKEN}"
    item = requests.get(url, params={"receiveTimeout": 50}, timeout=70).json()
    if item is None:
        continue
    try:
        handle(item["body"])
    finally:
        requests.delete(f"{BASE}/deleteNotification/{TOKEN}/{item['receiptId']}", timeout=30)

Node.js

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

async function handle(body) {
  if (body.typeWebhook !== "incomingMessageReceived") return;
  const data = body.messageData;
  if (data.typeMessage !== "textMessage") return;
  await fetch(`${base}/sendMessage/${GRATIO_TOKEN}`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      chatId: body.senderData.chatId,
      message: `Получили: ${data.textMessageData.textMessage}`,
      clientMessageId: `echo-${body.idMessage}`,
    }),
  });
}

for (;;) {
  const r = await fetch(`${base}/receiveNotification/${GRATIO_TOKEN}?receiveTimeout=50`);
  const item = await r.json();
  if (!item) continue;
  try {
    await handle(item.body);
  } finally {
    await fetch(`${base}/deleteNotification/${GRATIO_TOKEN}/${item.receiptId}`, { method: "DELETE" });
  }
}

clientMessageId защищает от дубля: если цикл упадёт после отправки и обработает то же уведомление снова, второго ответа не будет. Подробно — в статье Надёжная отправка без дублей.

Если не получилось

Ответ Причина Что сделать
null уведомлений нет напишите на номер ещё раз; увеличьте receiveTimeout
400 webhook_set у канала задан вебхук — очередь читает он снимите вебхук: setSettings с "webhookUrl": ""
одно и то же уведомление снова и снова оно не удалено вызовите deleteNotification с его receiptId

Что дальше

Очередь удобна для начала и для приложений без публичного адреса. Сервер с HTTPS может получать уведомления сразу — вебхуком.

Шаг 4. Уведомления на свой серверПринять уведомления вебхуком — обработчик на Python или Node.js, публичный адрес, настройка канала и проверка.

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