Уведомление — один объект JSON. Он одинаковый в очереди (поле body ответа receiveNotification), в теле вебхука и в доставке подписки. Формат — как у Green API, с полями сверх него: channel, eventId и новые виды уведомлений.
Пример
Мария пишет в личный чат MAX:
{
"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": "Здравствуйте! Есть места на субботу?"}
}
}
Общие поля
| Поле | Тип | Описание |
|---|---|---|
typeWebhook |
string | вид уведомления — таблица ниже |
instanceData |
object | канал, от которого пришло уведомление |
timestamp |
integer | время события, секунды Unix (UTC) |
idMessage |
string | id сообщения или события; есть не у всех видов |
eventId |
string | ключ события для защиты от повторной обработки; есть не у всех видов |
senderData |
object | чат и отправитель — у уведомлений о сообщениях |
messageData |
object | содержимое — у уведомлений о сообщениях |
Все id — строки, даже если выглядят как числа: id сообщений MAX 64-битные и в JavaScript и PHP числом теряют точность. Числа — только idInstance, timestamp и счётчики.
instanceData
| Поле | Описание |
|---|---|
idInstance |
номер канала, число |
wid |
аккаунт канала: номер 79990000001@c.us, у почты — адрес ящика. Пустая строка, если площадка номер не сообщила |
typeInstance |
v3 у MAX (как у Green API), telegram, whatsapp, email |
channel |
площадка: max, telegram, whatsapp, email |
Ветвитесь по channel: typeInstance нужен для совместимости с Green API.
Виды уведомлений
typeWebhook |
Что | senderData и messageData |
Статья |
|---|---|---|---|
incomingMessageReceived |
сообщение собеседника, его правка, удаление, реакция | есть | Текст и другие ниже |
outgoingMessageReceived |
своё сообщение с телефона; своя правка, удаление, реакция | есть | Свои сообщения |
outgoingAPIMessageReceived |
сообщение, отправленное через API | есть | Свои сообщения |
outgoingMessageStatus |
статус отправленного | нет, поля на верхнем уровне | outgoingMessageStatus |
stateInstanceChanged |
смена состояния канала | нет | stateInstanceChanged |
incomingCall, outgoingCall |
звонок | нет | incomingCall и outgoingCall |
callStateChanged |
ход звонка, который ведёт сервер Gratio | нет | callStateChanged |
groupEvent |
событие группы | нет | groupEvent |
syncGap |
после простоя дочитана не вся история | нет | syncGap |
senderData
| Поле | Личный чат | Группа | Канал (сообщество) |
|---|---|---|---|
chatId |
собеседник | группа | канал |
chatName |
имя собеседника | название группы | название канала |
chatType |
user; в Telegram чат с ботом — bot |
group |
channel |
sender |
собеседник | участник, который написал | автор, если площадка его сообщает; в Telegram — сам канал |
senderName |
имя собеседника | имя участника | имя автора или "" |
senderType |
всегда user |
user |
user |
senderContactName |
всегда "" — поле для совместимости с Green API |
"" |
"" |
senderPhoneNumber |
всегда 0; номер собеседника WhatsApp — в самом chatId |
0 |
0 |
chatId — куда отвечать: передайте его в sendMessage. Как выглядят адреса в каждой площадке — в статье Идентификаторы чатов и сообщений.
В своих сообщениях (outgoingMessageReceived, outgoingAPIMessageReceived) chatId — получатель, sender — аккаунт канала.
messageData
Вид содержимого — в messageData.typeMessage:
typeMessage |
Что | Статья |
|---|---|---|
textMessage |
текст | Текст |
quotedMessage |
ответ цитатой | Ответ цитатой |
extendedTextMessage |
пересланное, ссылка с превью | Ссылка и пересланное |
imageMessage, videoMessage, documentMessage, audioMessage, stickerMessage |
файл, голосовое, альбом | Файлы и альбомы |
contactMessage |
контакт | Контакт |
locationMessage |
геопозиция | Геопозиция |
pollMessage |
опрос | Опрос |
editedMessage |
правка | Правка |
deletedMessage |
удаление | Удаление |
reactionMessage |
реакция | Реакция |
У писем рядом с содержимым — emailMessageData: тема, цепочка, адресаты. См. Письмо.
Если сообщение отвечает на другое, в messageData есть quotedMessage — и у файла, и у геопозиции. Сообщение вида, который Gratio не разбирает, и служебные сообщения площадки (закреп, вход в чат) уведомлением не приходят. Изменения состава групп — отдельным groupEvent.
idMessage
| Уведомление | idMessage |
|---|---|
| сообщение | id сообщения на площадке: MAX "117428955282341903", Telegram "4815", WhatsApp "3EB0C767D26A1D5A6F0B", письмо "c62b698304229a98aad3" |
| правка | {id}:edit:{версия} — две правки одного сообщения дают разные id |
| удаление | {id}:delete |
| реакция | {id}:reaction:{автор}:{n} — n растёт при каждой смене и снятии реакции |
| статус | id отправленного сообщения |
| звонок | id звонка или записи о звонке — см. incomingCall и outgoingCall |
У правки, удаления и реакции сообщение, к которому относится событие, — в stanzaId внутри messageData.
eventId
eventId — ключ события в Gratio. Одно событие площадки — одно уведомление с одним eventId. Если ваше приложение может получить уведомление дважды (повтор вебхука после тайм-аута, падение до deleteNotification), храните обработанные ключи и пропускайте повторы.
| Уведомление | Вид eventId |
|---|---|
| сообщение | msg:{chat}:{id} |
| правка | edit:{chat}:{id}:{версия} |
| удаление | del:{chat}:{id} |
| реакция | react:{chat}:{id}:{автор}:{n} |
| звонок | call:{chat}:{id}:{outcome} |
| событие группы | msg:{chat}:{id} или grp:{chat}:{id} |
| ход звонка | callstate:{callId}:{state} |
| разрыв истории | gap:{reason}:{время}:{хеш} |
Разбирать eventId не нужно — сравнивайте строку целиком: внутри адрес чата во внутренней форме, без суффиксов WhatsApp.
У outgoingAPIMessageReceived, outgoingMessageStatus и stateInstanceChanged поля eventId нет. Ключ для них — idMessage, пара idMessage + status или хеш тела: повторная доставка приходит тем же телом.
Как разбирать
- Ветвитесь по
typeWebhook, затем поmessageData.typeMessage. - Незнакомый
typeWebhookилиtypeMessage— пропустите и подтвердите уведомление. Gratio добавляет новые виды и поля, старые не меняет. - Поля, которых у площадки нет, приходят пустыми (
"",0,null) или не приходят вовсе. Не полагайтесь на их наличие.
Пример разбора:
def on_notification(body: dict) -> None:
kind = body["typeWebhook"]
if kind in ("incomingMessageReceived", "outgoingMessageReceived", "outgoingAPIMessageReceived"):
data = body["messageData"]
handlers = {"textMessage": on_text, "editedMessage": on_edit, "reactionMessage": on_reaction}
handler = handlers.get(data["typeMessage"])
if handler is not None:
handler(body)
elif kind == "outgoingMessageStatus":
on_status(body["idMessage"], body["status"])
# остальные виды — пропустить, уведомление всё равно подтвердить
Что дальше
- Текст — самое частое уведомление целиком.
- Как получать уведомления — очередь, вебхук и подписки.
- Идентификаторы чатов и сообщений — адреса чатов в каждой площадке.
