Номер канала тоже пишет: сотрудник отвечает с телефона, приложение отправляет через API. Об этих сообщениях приходят свои уведомления, чтобы переписка в вашей системе была полной.
| С телефона или другого устройства | Через API | |
|---|---|---|
typeWebhook |
outgoingMessageReceived |
outgoingAPIMessageReceived |
typeMessage |
любой вид сообщения, правка, удаление, реакция | вид отправленного сообщения |
| Флаг настроек | outgoingMessageWebhook |
outgoingAPIMessageWebhook |
eventId |
есть | нет |
| Каналы | MAX, Telegram, WhatsApp, почта | MAX, Telegram, WhatsApp, почта |
С телефона
Сотрудник ответил Марии в MAX со своего телефона:
{
"typeWebhook": "outgoingMessageReceived",
"instanceData": {"idInstance": 7100000001, "wid": "79990000001@c.us", "typeInstance": "v3", "channel": "max"},
"timestamp": 1791823671,
"idMessage": "117428957013520467",
"eventId": "msg:8695836:117428957013520467",
"senderData": {
"chatId": "8695836", "chatName": "Мария", "chatType": "user",
"sender": "457747484", "senderName": "Школа робототехники", "senderType": "user",
"senderContactName": "", "senderPhoneNumber": 0
},
"messageData": {
"typeMessage": "textMessage",
"textMessageData": {"textMessage": "Да, на субботу в 11:00 есть два места."}
}
}
chatId — собеседник, sender — аккаунт канала в мессенджере, senderName — имя профиля канала. Содержимое — как у входящих: файлы, цитаты, геопозиция и другие виды из статьи Формат уведомления.
Свои правки, удаления и реакции, сделанные с телефона, приходят тем же outgoingMessageReceived — см. Правка, Удаление, Реакция.
Через API
Приложение отправило Марии сообщение методом sendMessage:
{
"typeWebhook": "outgoingAPIMessageReceived",
"instanceData": {"idInstance": 7100000001, "wid": "79990000001@c.us", "typeInstance": "v3", "channel": "max"},
"timestamp": 1791823671,
"idMessage": "117428956522361912",
"senderData": {
"chatId": "8695836", "chatName": "", "chatType": "user",
"sender": "79990000001", "senderName": "", "senderType": "user",
"senderContactName": "", "senderPhoneNumber": 0
},
"messageData": {
"typeMessage": "textMessage",
"textMessageData": {"textMessage": "Здравствуйте! Записали вас на субботу, 11:00."}
}
}
idMessage— тот же, что в ответеsendMessage.sender— номер канала цифрами (у WhatsApp —79990000001@c.us, у почты — адрес ящика).chatNameиsenderNameпустые.- Уведомление приходит сразу после ответа метода, следом — outgoingMessageStatus со
status: "sent". eventIdнет: ключ от повторной обработки —idMessage.
Отправили файл — typeMessage по типу файла, ссылка — в fileMessageData:
"messageData": {
"typeMessage": "documentMessage",
"fileMessageData": {
"downloadUrl": "https://api.gratio.net/media/7100000001/8695836/117428959906341277/0/b2c4…",
"caption": "Расписание на октябрь", "fileName": "Расписание.pdf", "jpegThumbnail": "",
"isAnimated": false, "mimeType": "application/pdf", "forwardingScore": 0, "isForwarded": false
}
}
Ответили цитатой (quotedMessageId) — typeMessage: "quotedMessage", как у входящего ответа (см. Ответ цитатой), с participant: "".
Как отличить
| Вопрос | Ответ |
|---|---|
| сообщение отправило приложение или человек с телефона | по typeWebhook: outgoingAPIMessageReceived или outgoingMessageReceived |
| статус относится к сообщению через API | поле sendByApi в outgoingMessageStatus |
| в истории чата | поле sendByApi у элемента журнала — см. Элемент журнала |
Сообщение, отправленное через API, второй раз как outgoingMessageReceived не приходит, даже когда мессенджер присылает его эхо.
Отправка ответила 503 outcome_unknown, а сообщение потом нашлось на площадке — outgoingAPIMessageReceived и sent придут позже, когда Gratio его найдёт. Подробно — Надёжная отправка без дублей.
В других каналах
| Канал | sender у сообщения с телефона |
|---|---|
| MAX | id аккаунта канала в MAX |
| Telegram | id аккаунта в Telegram; senderName пустой. Сообщения в «Избранное» — тоже outgoingMessageReceived, chatName — «Избранное» |
номер канала 79990000001@c.us |
|
| Почта | адрес ящика; приходят письма из «Отправленных» и ответы из почтовой программы — см. Письмо |
Как обработать
Добавить в диалог CRM ответы сотрудника с телефона и не задвоить отправленное через API:
def on_outgoing(body: dict) -> None:
kind = body["typeWebhook"]
if kind not in ("outgoingMessageReceived", "outgoingAPIMessageReceived"):
return
data = body["messageData"]
if data["typeMessage"] != "textMessage":
return
chat_id = body["senderData"]["chatId"]
if message_exists(chat_id, body["idMessage"]): # уже записали при отправке через API
return
add_operator_message(
chat_id,
body["idMessage"],
data["textMessageData"]["textMessage"],
source="api" if kind == "outgoingAPIMessageReceived" else "phone",
)
Что дальше
- outgoingMessageStatus — доставлено и прочитано.
- sendMessage — отправить сообщение.
- Переписка в своей CRM — вся переписка канала в CRM.
