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

subscriptions

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

Подписка — копия ленты уведомлений канала по своему адресу. Очередь и вебхук канала при этом не меняются: основное приложение читает свою ленту, а CRM, аналитика или архив получают ту же ленту отдельно. Каждую доставку Gratio подписывает.

Создать или изменить POST /waInstance{idInstance}/subscriptions/{apiTokenInstance}
Список GET /waInstance{idInstance}/subscriptions/{apiTokenInstance}
Снять DELETE /waInstance{idInstance}/subscriptions/{apiTokenInstance}/{subscriptionId}
Тело JSON
Каналы MAX, Telegram, WhatsApp, почта

Те же запросы работают по адресу /v1/instances/{idInstance}/subscriptions с заголовком Authorization: Bearer {apiTokenInstance}.

Параметры

Тело POST:

Параметр Тип Обязательный Описание
name string да имя подписки: латиница, цифры, ., _, -, до 64 символов. Имена на gratio- заняты
url string да куда доставлять: https:// или http://, до 500 символов, публичный хост
secret string нет секрет подписи, 16–128 символов. Не передали — Gratio создаст его и вернёт один раз в ответе

Подписка с таким name уже есть — POST меняет её адрес и секрет, очередь доставки сохраняется. POST без secret выдаёт новый секрет: подпись старым перестаёт сходиться сразу.

Пример запроса

Подписать CRM на ленту канала, секрет создаст Gratio:

curl

curl -X POST "$GRATIO_URL/waInstance$GRATIO_ID/subscriptions/$GRATIO_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "crm",
    "url": "https://crm.example.ru/hooks/gratio"
  }'

Python

import os
import requests

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

url = f"{BASE}/subscriptions/{TOKEN}"
payload = {"name": "crm", "url": "https://crm.example.ru/hooks/gratio"}
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}/subscriptions/${GRATIO_TOKEN}`;
const payload = { name: "crm", url: "https://crm.example.ru/hooks/gratio" };
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 . '/subscriptions/' . getenv('GRATIO_TOKEN');
$payload = ['name' => 'crm', 'url' => 'https://crm.example.ru/hooks/gratio'];

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

Пример ответа

Ответ 200 OK:

{
  "id": "sub_9f2c41d07be35a1c86e4f0b2",
  "name": "crm",
  "url": "https://crm.example.ru/hooks/gratio",
  "createdAt": 1791823700,
  "pending": 0,
  "oldestPendingAt": null,
  "dead": 0,
  "lastDeliveredAt": null,
  "lastError": null,
  "lastErrorAt": null,
  "system": false,
  "created": true,
  "secret": "a39e8979effc76a1915fb07c5e3b1d7ada556f9f12974f89312a3486ebe83095"
}

Сохраните secret сразу: Gratio показывает его только в этом ответе.

Поля ответа

Поле Тип Описание
id string id подписки — для DELETE и заголовка X-Gratio-Subscription
name, url string имя и адрес доставки
createdAt integer когда подписку создали, секунды Unix
pending integer сколько уведомлений ждут доставки. В ответе POST — всегда 0, точное число — в списке
oldestPendingAt integer или null время самого старого недоставленного
dead integer сколько уведомлений подписка отвергла — отравленные
lastDeliveredAt integer или null последняя удачная доставка
lastError, lastErrorAt string или null, integer или null последняя причина неудачи (HTTP 500, ConnectTimeout, internal_host) и её время
system boolean true — служебная подписка Gratio: видна в списке, менять и снимать её ключом канала нельзя
created boolean true — подписку создали, false — изменили существующую
secret string секрет подписи; только если его создал Gratio

Ещё примеры

Список подписок

Все подписки канала с очередью доставки:

curl "$GRATIO_URL/waInstance$GRATIO_ID/subscriptions/$GRATIO_TOKEN"

Ответ 200 OK — подписки по времени создания, со счётчиками доставки:

{
  "subscriptions": [
    {
      "id": "sub_9f2c41d07be35a1c86e4f0b2",
      "name": "crm",
      "url": "https://crm.example.ru/hooks/gratio",
      "createdAt": 1791823700,
      "pending": 2,
      "oldestPendingAt": 1791823905,
      "dead": 0,
      "lastDeliveredAt": 1791823890,
      "lastError": "HTTP 503",
      "lastErrorAt": 1791823906,
      "system": false
    }
  ]
}

Секрет в списке не показывается.

Свой секрет

Секрет задаёте сами — например, чтобы хранить его в своём хранилище секретов заранее:

curl -X POST "$GRATIO_URL/waInstance$GRATIO_ID/subscriptions/$GRATIO_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{
    "name": "crm",
    "url": "https://crm.example.ru/hooks/gratio",
    "secret": "5d0c3f1a9b7e4c2d8a6f0e1b3c5d7e9f"
  }'

В ответе нет поля secret.

Снять подписку

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

curl -X DELETE "$GRATIO_URL/waInstance$GRATIO_ID/subscriptions/$GRATIO_TOKEN/sub_9f2c41d07be35a1c86e4f0b2"

Ответ 200 OK:

{"removed": true}

Недоставленные уведомления подписки удаляются вместе с ней.

Доставка

Gratio шлёт POST на url. Тело — уведомление целиком (как body в receiveNotification), компактный JSON в UTF-8.

Заголовок Значение
Content-Type application/json
X-Gratio-Signature t=<время>,v1=<подпись> — как проверить, см. Проверка подписи
X-Gratio-Instance idInstance канала
X-Gratio-Subscription id подписки
X-Gratio-Delivery номер доставки; повтор приходит с тем же номером
  • Уведомления идут по одному, в порядке записи: следующее — после 2xx на текущее. Подписки канала доставляются независимо друг от друга.
  • Подписка получает уведомления, записанные после её создания.
  • Набор уведомлений — тот же, что у очереди канала: флаги setSettings действуют и на подписки.
  • Gratio ждёт ответа до 30 секунд.
Ответ Что сделает Gratio
2xx доставлено
408, 429, 5xx, тайм-аут, сбой сети повтор через 1, 5, 15, 60 и 300 секунд, дальше каждые 5 минут, пока уведомлению нет 24 часов; потом оно истекает
3xx и другие 4xx повтор по тому же расписанию; набралось 5 неудачных попыток — уведомление уходит в отравленные подписки, очередь идёт дальше
адрес стал вести во внутреннюю сеть как 4xx, причина — internal_host

Отравленные подписки видно только счётчиком dead в списке: посмотреть и вернуть их пока нельзя. Доставленные, отравленные и истёкшие уведомления подписки хранятся 7 дней.

Повтор отсекайте по X-Gratio-Delivery или по eventId уведомления.

Ошибки

Код code Когда Что делать
400 validation нет name или url; имя не по правилам; url не http(s) или длиннее 500; secret короче 16 или длиннее 128; DELETE без id исправить запрос
400 bad_url адрес ведёт во внутреннюю сеть дать публичный адрес
401 — неверный idInstance или токен взять ключ в кабинете
403 reserved имя на gratio- или служебная подписка Gratio выбрать другое имя
404 not_found DELETE: подписки с таким id нет проверить id в списке
409 limit у канала уже 5 подписок, служебные тоже считаются снять ненужную

Что дальше

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