Номеру канала звонят или с телефона номера позвонили. Gratio присылает два события: «звонит» и итог. По ним ведут журнал звонков в CRM и перезванивают на пропущенные.
typeWebhook |
incomingCall — звонят номеру; outgoingCall — звонили с номера |
typeMessage |
— |
| Флаг настроек | incomingCallWebhook — для обоих |
| Каналы | MAX, Telegram, WhatsApp |
Пример
Мария позвонила в MAX, разговор длился 11 секунд:
{
"typeWebhook": "incomingCall",
"instanceData": {"idInstance": 7100000001, "wid": "79990000001@c.us", "typeInstance": "v3", "channel": "max"},
"timestamp": 1791826111,
"idMessage": "117429100333960555",
"from": "8695836@c.us",
"chatId": "8695836",
"status": "hangUp",
"outcome": "completed",
"durationSeconds": 11,
"isVideo": false,
"eventId": "call:8695836:117429100333960555:completed"
}
Пока звонок звонит, приходит такое же уведомление со status: "offer":
{
"typeWebhook": "incomingCall",
"instanceData": {"idInstance": 7100000001, "wid": "79990000001@c.us", "typeInstance": "v3", "channel": "max"},
"timestamp": 1791826098,
"idMessage": "31A9ADA2-3889-4B2B-9D88-6A7142875D7F",
"from": "8695836@c.us",
"chatId": "8695836",
"status": "offer",
"outcome": "ringing",
"durationSeconds": 0,
"isVideo": false,
"eventId": "call:8695836:31A9ADA2-3889-4B2B-9D88-6A7142875D7F:ringing"
}
Поля
| Поле | Описание |
|---|---|
chatId |
собеседник — тот, кто звонил или кому звонили |
from |
звонящий с суффиксом @c.us — поле для совместимости с Green API; опирайтесь на chatId |
status |
итог в терминах Green API — таблица ниже |
outcome |
итог подробнее — таблица ниже |
durationSeconds |
длительность разговора в секундах; 0, если разговора не было |
isVideo |
видеозвонок |
idMessage |
у offer — id звонка, у итога — id записи о звонке в чате |
У звонка нет senderData и messageData.
Итоги
status |
outcome |
Что значит |
|---|---|---|
offer |
ringing |
звонит сейчас |
hangUp |
completed |
разговор состоялся, длительность — durationSeconds |
hangUp |
failed |
соединение прервалось — разговора могло и не быть, лучше перезвонить. Только Telegram |
missed |
missed |
не ответили |
missed |
canceled |
звонящий сбросил, не дождавшись ответа |
declined |
rejected |
звонок отклонили |
declined |
busy |
занято |
id звонка
| Канал | idMessage у offer |
idMessage у итога |
|---|---|---|
| MAX | id звонка, "31A9ADA2-3889-4B2B-9D88-6A7142875D7F" |
id записи о звонке в чате |
| Telegram | "call-…" с номером звонка |
номер служебного сообщения о звонке |
"call-…" с id звонка |
"call-…-end" |
idMessage из offer — это callId для answerCall и rejectCall, если канал умеет звук звонков. В истории чата звонок — элемент с typeMessage: "callMessage".
В других каналах
- MAX. Итог приходит, когда MAX создаёт запись о звонке. Очень короткий сброс MAX иногда не записывает — тогда будет только
offer. - Telegram. Звук звонков Gratio в Telegram не ведёт — приходят только события.
- WhatsApp.
chatIdиfrom—"79991234567@c.us". Ответили на телефоне —durationSeconds: 0: конец разговора связанное устройство не видит.
Ответить самому
Пока звонок в offer, приложение может ответить сервером Gratio, проиграть приветствие и записать разговор, если в getCapabilities есть call_audio: true. Ход такого звонка приходит уведомлениями callStateChanged. Подробно — Звонки: как это работает.
Как обработать
Вести журнал звонков и создавать задачу на пропущенный:
def on_call(body: dict) -> None:
kind = body["typeWebhook"]
if kind not in ("incomingCall", "outgoingCall"):
return
if body["status"] == "offer":
show_ringing(body["chatId"], call_id=body["idMessage"])
return
log_call(
chat_id=body["chatId"],
direction="in" if kind == "incomingCall" else "out",
outcome=body["outcome"],
seconds=body["durationSeconds"],
at=body["timestamp"],
)
if kind == "incomingCall" and body["outcome"] in ("missed", "canceled", "failed"):
create_callback_task(body["chatId"])
Что дальше
- callStateChanged — ход звонка, который ведёт сервер.
- answerCall — ответить на звонок через API.
- Звонки: автоответчик и голосовой бот — бот, который отвечает на звонки.
