Webhook endpoints создаются в /my/webhooks. Bridge отправляет событие на активные endpoints проекта, подписанные на нужные event types: message.inbound, message.deleted, message.read, message.interaction и другие служебные события. Доставка идет через BullMQ: до 5 попыток с exponential backoff.
Повтор доставки доступен в кабинете: откройте /my/activity/events/{event_id} и используйте retry одной delivery или Повторить failed deliveries для endpoints, у которых latest delivery по событию сейчас failed.
Content-Type: application/json
User-Agent: Bridge-Webhook/0.1
X-Bridge-Event-Id: <event_id>
X-Bridge-Event-Type: <event_type>
X-Bridge-Timestamp: <unix_seconds>
X-Bridge-Signature: v1=<hmac_sha256_hex>
Проверка подписи
Подписывается raw body, а не распарсенный JSON. Timestamp нужно проверять на допустимое окно времени на стороне получателя.
signed_payload = X-Bridge-Timestamp + '.' + raw_request_body
expected = 'v1=' + hmac_sha256_hex(webhook_secret, signed_payload)
secure_compare(expected, X-Bridge-Signature)
message.inbound: reply / forwarded
В message.inbound поля message.reply_to и message.forwarded уже входят в стабильный v1 contract. Telegram и WhatsApp заполняют их best-effort, а MAX пока оставляет эти поля как reserved slots.
{
"event_id": "event-uuid",
"type": "message.inbound",
"project_id": "project-uuid",
"provider": "telegram",
"occurred_at": "2026-04-24T10:00:00.000Z",
"data": {
"channel_id": "channel-uuid",
"channel_type": "telegram_qr_bridge",
"message": {
"id": "123",
"text": "Здравствуйте",
"type": "text",
"has_media": false,
"date": "2026-04-24T10:00:00.000Z",
"reply_to": null,
"forwarded": null
},
"from": {
"external_id": "telegram-user-id",
"display_name": "Иван Петров"
},
"chat": {
"external_id": "telegram-chat-id",
"type": "private",
"display_name": "Иван Петров"
},
"attachments": []
}
}
message.interaction
message.interaction уже публикуется для WhatsApp reactions на сообщения, которые были отправлены через Bridge. Для Telegram и MAX этот event пока остается неподключенным.
{
"event_id": "event-uuid",
"type": "message.interaction",
"project_id": "project-uuid",
"provider": "whatsapp",
"occurred_at": "2026-04-24T10:05:00.000Z",
"data": {
"channel_id": "channel-uuid",
"channel_type": "whatsapp_qr_bridge",
"message": {
"id": "message-uuid",
"provider_message_id": "wamid.HBgLNQ..."
},
"actor": {
"external_id": "79001234567@s.whatsapp.net",
"display_name": null
},
"interaction": {
"type": "reaction",
"action": "added",
"key": "🔥"
}
}
}
message.read
message.read уже публикуется для WhatsApp read receipts и для Telegram read best-effort по raw updates. Сейчас event привязан к сообщениям, которые Bridge сам отправил во внешний канал.
{
"event_id": "event-uuid",
"type": "message.read",
"project_id": "project-uuid",
"provider": "whatsapp",
"occurred_at": "2026-04-24T10:06:00.000Z",
"data": {
"channel_id": "channel-uuid",
"channel_type": "whatsapp_qr_bridge",
"message": {
"id": "message-uuid",
"provider_message_id": "wamid.HBgLNQ..."
},
"reader": {
"external_id": "79001234567@s.whatsapp.net",
"display_name": null
},
"read": {
"read_at": "2026-04-24T10:06:00.000Z"
}
}
}
message.deleted
message.deleted уже публикуется для WhatsApp revoke/delete. Bridge best-effort находит исходное сообщение по provider_message_id, поэтому в data.message.id может прийти внутренний Bridge id удаленного сообщения.
{
"event_id": "event-uuid",
"type": "message.deleted",
"project_id": "project-uuid",
"provider": "whatsapp",
"occurred_at": "2026-04-29T08:10:00.000Z",
"data": {
"channel_id": "channel-uuid",
"channel_type": "whatsapp_qr_bridge",
"message": {
"id": "bridge-message-uuid",
"provider_message_id": "AC481C91312A67417E4EC4733127442E"
},
"actor": {
"external_id": null,
"display_name": null
},
"deleted": {
"deleted_at": "2026-04-29T08:10:00.000Z",
"scope": "for_everyone",
"direction": "outbound"
}
}
}