---
title: "Вебхуки WhatsApp: события, безопасность и повторные доставки"
description: "Как работают вебхуки WhatsApp: события сообщений и статусов, надёжный обработчик, проверка подписи Meta, повторы, идемпотентность и пропущенные события."
canonical: "https://omnichannels.ai/ru/blog/whatsapp-webhooks-guide/"
language: "ru"
updated: "2026-10-16"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
category: "integration"
primaryQuery: "вебхук whatsapp"
keywords: ["вебхук whatsapp business api", "события статусов вебхука whatsapp", "x-hub-signature-256 whatsapp", "повторные доставки вебхука whatsapp", "вебхук статуса доставки whatsapp", "идемпотентный обработчик вебхуков", "вебхук входящих сообщений whatsapp"]
published: "2026-10-16"
author: "OmniChannels.ai Editorial Team"
reviewer: "BroadNet Messaging Solutions Team"
readingMinutes: 10
answer: "Вебхук WhatsApp — это HTTPS-эндпоинт на вашем сервере, который получает события: статусы доставки отправленных вами сообщений и сообщения от клиентов. В OmniChannels.ai статусы приходят как SUBMITTED, SENT, DELIVERED, READ, FAILED или REJECTED. Сохраняйте исходное тело, быстро отвечайте 2xx, устраняйте дубликаты по идентификатору сообщения и обрабатывайте асинхронно. Meta подписывает свои вебхуки; в нашей документации заголовок подписи не определён, поэтому защищайте эндпоинт на уровне транспорта и приложения."
takeaways: ["Вебхуки доставляют статусы и входящие сообщения на ваш HTTPS-эндпоинт, так что опрос не нужен; статусы WhatsApp приводятся к SUBMITTED, SENT, DELIVERED, READ, FAILED и REJECTED.", "Надёжный обработчик делает три вещи по порядку: сохраняет исходное событие, возвращает 2xx, затем обрабатывает асинхронно и идемпотентно.", "Статусы могут приходить не по порядку или дважды, поэтому ранжируйте их и никогда не позволяйте запоздавшему SENT перезаписать сохранённый DELIVERED.", "Meta подписывает вебхуки, отправляемые приложениям, заголовком X-Hub-Signature-256, но в спецификации API OmniChannels.ai подпись вебхука не определена, поэтому используйте HTTPS, неугадываемый путь и проверку тела.", "Если события пропущены, читайте статус WhatsApp по пакету через эндпоинт bulk-insights, а не отправляйте сообщения заново."]
faq: 
  - q: "Что такое вебхук WhatsApp?"
    a: "Вебхук WhatsApp — это URL на вашем сервере, который платформа вызывает HTTP POST-запросом всякий раз, когда что-то происходит, например сообщение доставлено, прочитано или не доставлено, либо клиент написал вам. Он заменяет опрос. Вы открываете HTTPS-эндпоинт, передаёте его провайдеру и обрабатываете JSON-события, которые он получает."
  - q: "Как проверить подпись вебхука WhatsApp?"
    a: "Для вебхука, который Meta отправляет напрямую вашему приложению, документация Meta предписывает вычислить HMAC-SHA256 от исходной полезной нагрузки с секретом вашего приложения и сравнить его с заголовком X-Hub-Signature-256. Для вебхука OmniChannels.ai в спецификации API заголовок подписи не определён, поэтому полагайтесь на HTTPS, неугадываемый путь и проверку тела."
  - q: "Что будет, если мой эндпоинт вебхука недоступен?"
    a: "Документация Meta сообщает, что она повторяет неудачные доставки со всё меньшей частотой до 7 дней, что может приводить к дубликатам. Для событий нашей платформы уточните поведение повторов у инженера по подключению и используйте эндпоинт bulk-insights, чтобы читать статус WhatsApp по каждому получателю пакета. Для SMS эндпоинт resendDlr повторно отправляет отчёты."
  - q: "Как обрабатывать дубликаты событий вебхука?"
    a: "Сделайте обработку идемпотентной. Найдите сообщение по идентификатору, сравните ранг входящего статуса с сохранённым и игнорируйте события, не продвигающие состояние. Двукратное применение одного события должно давать тот же эффект, что и однократное. Храните исходное тело каждого события, чтобы повторно воспроизвести его после исправления ошибки."
  - q: "Как быстро должен отвечать мой эндпоинт?"
    a: "В течение нескольких секунд. Сохраните исходное событие, верните 2xx, а основную работу выполняйте в очереди или воркере. Не вызывайте другие сервисы, не отправляйте сообщения и не выполняйте тяжёлые запросы до ответа. Если хранилище недоступно, верните 5xx, чтобы отправитель мог повторить, а не подтверждайте событие, которое вы потеряли."
  - q: "Можно ли использовать вебхук для автоматического ответа?"
    a: "Да, но не изнутри обработчика. Подтвердите событие, а решение об ответе принимайте в отдельном задании. Внутри 24-часового окна обслуживания клиента можно отправить свободное сообщение; вне его нужен одобренный шаблон. Никогда не отправляйте сообщение повторно из самого обработчика вебхука, чтобы избежать циклов и дубликатов."
sources: 
  - title: "Webhooks overview — WhatsApp Business Platform, Meta for Developers"
    url: "https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/overview"
  - title: "Create a webhook endpoint — WhatsApp Business Platform, Meta for Developers"
    url: "https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/create-webhook-endpoint"
  - title: "RFC 2104: HMAC: Keyed-Hashing for Message Authentication"
    url: "https://www.rfc-editor.org/rfc/rfc2104"
---

# Вебхуки WhatsApp: события, безопасность и повторные доставки

Canonical: https://omnichannels.ai/ru/blog/whatsapp-webhooks-guide/
Language: ru
Publisher: OmniChannels.ai by BroadNet Technologies

Это руководство для инженеров, которым нужно надёжно получать события WhatsApp: статусы доставки отправляемых сообщений и входящие сообщения от клиентов. В нём объясняется, как работают вебхуки, что строить в обработчике, чем безопасность вебхуков Meta отличается от наших и что делать, когда события пропадают.

## Что такое вебхуки WhatsApp и зачем они нужны?

Вебхуки WhatsApp — это HTTP-колбэки. Когда сообщение меняет состояние или клиент пишет вам, платформа отправляет на ваш эндпоинт `POST` с JSON-телом. Опрашивать ничего не нужно, а события вы видите по мере их возникновения.

Важны два семейства событий:

- **События статусов** для отправленных вами сообщений: в очереди, отправлено, доставлено, прочитано, не доставлено.
- **Входящие сообщения** от клиентов, которые открывают или продлевают 24-часовое окно обслуживания клиента. См. наше [руководство об окне](/ru/blog/whatsapp-24-hour-customer-service-window/).

Вызов отправки лишь сообщает, что сообщения поставлены в очередь. О том, что произошло с каждым получателем, вы узнаёте из вебхука.

## Какие события и статусы я буду получать?

В OmniChannels.ai каждый канал сообщает одни и те же нормализованные статусы, поэтому один обработчик может обслуживать WhatsApp, SMS и остальные каналы.

| Статус | Значение | Финальный? |
|---|---|---|
| `SUBMITTED` | Принято платформой и поставлено в очередь | Нет |
| `SENT` | Передано в канал | Нет |
| `DELIVERED` | Подтверждено на устройстве получателя | Обычно; может последовать `READ` |
| `READ` | Открыто получателем, если канал сообщает о прочтении | Да |
| `FAILED` | Не доставлено; событие содержит причину, если она доступна | Да |
| `REJECTED` | Отклонено, например из-за заблокированного содержимого или незарегистрированного отправителя | Да |

Считайте статусы последовательностью, которая может приходить не по порядку, и ожидайте появления новых значений. Не допускайте сбоя на незнакомом статусе. См. [статусы доставки сообщений](/ru/blog/message-delivery-status-explained/).

## Как настроить эндпоинт?

Откройте HTTPS-эндпоинт, передайте URL провайдеру, затем протестируйте на собственном номере.

1. Создайте эндпоинт, принимающий `POST` с JSON-телом, например `https://api.example.com/webhooks/omnichannels`.
2. Отправьте URL нашей команде или администратору аккаунта для настройки в вашем аккаунте. У реселлеров может быть отдельный вебхук на каждый субаккаунт.
3. Отправьте тестовое сообщение на свой номер и убедитесь, что события приходят.

При разработке туннель вроде ngrok даёт вашему локальному серверу публичный HTTPS URL. Если вы дополнительно подключаете приложение напрямую к Meta, проверка эндпоинта Meta — отдельный шаг: `GET`-запрос с токеном проверки и значением `hub.challenge`, на который вы отвечаете `200` с этим значением, как описано в [документации Meta по эндпоинту вебхука](https://developers.facebook.com/documentation/business-messaging/whatsapp/webhooks/create-webhook-endpoint).

## Как выглядит payload?

Он зависит от канала. В спецификации API нет единой схемы вебхука, поэтому сначала логируйте исходное тело и сопоставляйте нужные поля по реальным событиям в вашем аккаунте. Пример показывает, какую информацию несёт событие доставки, и носит только иллюстративный характер.

```json
{
  "messageId": "2603121407537573731",
  "channel": "SMS",
  "destination": "447700900123",
  "status": "DELIVERED",
  "timestamp": "2026-10-10T09:15:42Z",
  "reason": null
}
```

Не пишите код под эти имена полей, не проверив реальное событие. Попросите у инженера по подключению примеры payload для каждого канала и сохраните их как тестовые фикстуры. Более широкая документация — в [справочнике по вебхукам](/developers/webhooks/).

## Как написать надёжный обработчик?

Сделайте три вещи по порядку: сохраните исходное событие, подтвердите ответом `2xx`, затем обработайте асинхронно. Обработчик ниже следует шаблону из нашей документации.

```js
import express from "express";

const app = express();

// Сохраняйте исходное тело, чтобы хранить его точно в том виде, в каком оно получено.
app.post(
  "/webhooks/omnichannels",
  express.json({ verify: (req, _res, buf) => { req.rawBody = buf.toString("utf8"); } }),
  async (req, res) => {
    try {
      await db.webhookEvents.insert({ receivedAt: new Date(), body: req.rawBody });
    } catch (err) {
      return res.sendStatus(500); // хранилище недоступно: пусть событие повторят
    }
    res.sendStatus(200);          // подтверждайте быстро
    queue.publish("status-events", req.body); // основную работу выполняйте в другом месте
  },
);

// Воркер: идемпотентная обработка
async function processEvent(event) {
  const id = event.messageId ?? event.message_id ?? event.id; // сопоставляйте по каналу
  const status = event.status;
  const rank = { SUBMITTED: 1, SENT: 2, DELIVERED: 3, READ: 4, FAILED: 4, REJECTED: 4 };

  const current = await db.messages.findOne({ providerId: id });
  if (!current) return; // неизвестное сообщение: залогируйте и разберитесь
  if ((rank[status] ?? 0) <= (rank[current.status] ?? 0)) return; // дубликат или устаревшее событие

  await db.messages.update({ providerId: id }, { status, updatedAt: new Date() });
}
```

```python
from datetime import datetime, timezone
from flask import Flask, request

app = Flask(__name__)

RANK = {"SUBMITTED": 1, "SENT": 2, "DELIVERED": 3, "READ": 4, "FAILED": 4, "REJECTED": 4}


@app.post("/webhooks/omnichannels")
def omnichannels_webhook():
    raw = request.get_data(as_text=True)
    try:
        db.webhook_events.insert({"received_at": datetime.now(timezone.utc), "body": raw})
    except Exception:
        return "", 500           # хранилище недоступно: пусть событие повторят
    queue.publish("status-events", raw)  # обрабатывайте асинхронно
    return "", 200               # подтверждайте быстро
```

Объекты `db` и `queue` — ваше собственное хранилище и очередь заданий. Карта `rank` делает обработку идемпотентной: дубликат или устаревшее событие не продвигает состояние, поэтому игнорируется.

### Правила надёжного обработчика

- **Отвечайте в течение нескольких секунд.** Не выполняйте тяжёлую работу до ответа.
- **Возвращайте `2xx` только после сохранения события.** Если хранилище недоступно, возвращайте `5xx`.
- **Устраняйте дубликаты по идентификатору сообщения.** Один и тот же статус может прийти несколько раз.
- **Никогда не отправляйте сообщение повторно из обработчика.** Решения о повторах принимайте в отдельном задании, проверив статус.
- **Храните исходное тело** для разбора проблем и для повторного воспроизведения событий после исправления.

## Как защитить вебхук WhatsApp?

Это зависит от того, кто отправляет на ваш эндпоинт. Meta подписывает вебхуки, которые отправляет зарегистрированным вами в Meta приложениям. В спецификации API OmniChannels.ai заголовок подписи вебхука не определён, поэтому не ждите его.

| | Meta на ваше приложение | OmniChannels.ai на ваш эндпоинт |
|---|---|---|
| Подпись | Заголовок `X-Hub-Signature-256` согласно документации Meta | Не определена в спецификации API |
| Проверка | HMAC-SHA256 исходной полезной нагрузки с секретом приложения, сравнение с заголовком | Не применимо |
| Ваши меры | Проверять подпись при каждом `POST` | HTTPS с действительным сертификатом, неугадываемый путь, строгая проверка тела |

Для схемы Meta документация Meta предписывает сформировать хеш HMAC-SHA256 от JSON-нагрузки с секретом приложения и сравнить его со значением после `sha256=` в заголовке `X-Hub-Signature-256`. Сам HMAC определён в RFC 2104. Вычисляйте его над исходными байтами, а не над повторно сериализованным объектом, и сравнивайте за постоянное время.

Для нашего эндпоинта:

- Используйте только HTTPS с действительным сертификатом.
- Используйте длинный неугадываемый путь и меняйте его при утечке.
- Проверяйте структуру тела и отклоняйте всё неожиданное.
- Считайте события уведомлениями. Перед необратимым действием, например возвратом средств или блокировкой по подозрению в фроде, подтвердите состояние запросом.

## Что происходит при сбое доставки?

Повторы зависят от отправителя. Документация Meta сообщает, что она повторяет неудачную доставку со всё меньшей частотой до 7 дней, что может приводить к дубликатам уведомлений. Это повод быть идемпотентным, даже если дубликаты вы видите редко. Для событий нашей платформы уточните поведение повторов у инженера по подключению, а не считайте его таким же, как у Meta.

В любом случае проектируйте систему с учётом потери так же, как и дублирования: эндпоинт может быть недоступен при развёртывании, а правило файрвола может молча отбрасывать запросы.

## Как восстановить пропущенные события?

Опрашивайте пакет, а не отправляйте сообщение заново.

| Что нужно | Вызов | Примечания |
|---|---|---|
| Прочитать статус WhatsApp по каждому получателю | `GET /whatsapp/message/bulk-insights` | Фильтр пакета по `status` или `destination`; пагинация через `page` и `size` |
| Повторно отправить отчёты о доставке SMS | `POST /sms/resendDlr` | Фильтры `startDate`, `endDate`, `senderId` и `messageStatus` |

```bash
curl "https://api.broadnet.me/whatsapp/message/bulk-insights?batch_Id=2609091405000000001&page=0&size=100" \
  -H "Authorization: Bearer $BROADNET_TOKEN"
```

`batch_Id` — это идентификатор, который вернул вызов отправки, а `page` нумеруется с нуля. Запускайте ночную сверку, которая читает пакеты за предыдущий день и заполняет пробелы.

### Чек-лист диагностики

1. URL настроен в нужном аккаунте или субаккаунте?
2. Эндпоинт доступен по HTTPS с действительным сертификатом?
3. Он быстро отвечает `2xx` или срабатывает тайм-аут?
4. Запросы не блокирует правило файрвола или WAF?
5. Вы логируете исходное тело до разбора, чтобы ошибка парсера не скрыла событие?

## Пример: конвейер уведомлений ритейлера

«Souq Rafiq» (условный пример), розничный продавец из ОАЭ, отправляет обновления по заказам в WhatsApp и хочет получать точный статус в своей системе заказов.

1. Заказы отправляются через `sendbulk`, а `batchId` сохраняется в заказе. См. [отправку сообщения WhatsApp через API](/ru/blog/send-whatsapp-message-api-examples/).
2. Эндпоинт вебхука записывает каждое событие в таблицу, затем возвращает `200`.
3. Воркер ранжирует статусы и обновляет состояние сообщения в заказе.
4. События `FAILED` создают задачу для поддержки с указанием причины, а переход на SMS рассматривается по [стратегии резервных каналов](/ru/blog/channel-fallback-strategy/).
5. Входящие сообщения клиентов направляются в общий инбокс, чтобы операторы могли ответить внутри окна.
6. Ночное задание вызывает `bulk-insights` по вчерашним пакетам и исправляет всё пропущенное.

## Какие типичные ошибки?

- **Тяжёлая работа до ответа,** которая вызывает тайм-ауты и повторные доставки.
- **Подтверждение до сохранения,** из-за которого события теряются при сбое хранилища.
- **Доверие порядку.** Запоздавший `SENT` перезаписывает `DELIVERED`.
- **Код под иллюстративный payload** вместо реальных событий.
- **Повторная сериализация JSON до проверки подписи,** которая меняет байты.
- **Повторная отправка из обработчика,** которая может зациклиться.
- **Ограничения:** это руководство описывает наше документированное поведение. Политику повторов и поля payload для вашего аккаунта нужно подтвердить при подключении.

## Как помогает OmniChannels.ai

OmniChannels.ai отправляет статусы доставки и входящие сообщения WhatsApp, SMS, RCS и других каналов на ваш вебхук в едином нормализованном формате, с отдельными вебхуками на субаккаунты для реселлеров. BroadNet — официальный Meta Business Solution Provider, поэтому собственные требования Meta к вебхукам выполняются за вас, а вы работаете с нашим API. Читайте [справочник по вебхукам](/developers/webhooks/) и [документацию WhatsApp API](/developers/whatsapp/) или посмотрите, как события отображаются в [общем инбоксе](/ru/platform/unified-inbox/).
