> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ycloud.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Рекомендации по API сообщений WhatsApp

> Создавайте надежные, соответствующие правилам и наблюдаемые рабочие процессы отправки сообщений WhatsApp для продакшена.

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

## Перед началом работы

* Подключите и зарегистрируйте бизнес-номера телефонов WhatsApp, с которых будут отправляться сообщения.
* Сохраните свой API-ключ YCloud на сервере.
* Настройте подписанный эндпоинт Webhook для `whatsapp.message.updated`.
* Определите, как ваша система фиксирует согласие, отказы от рассылки, цель сообщений и сроки хранения данных.
* Назначьте ответственных за отправку, обработку Webhook и реагирование на инциденты.

## Выбор эндпоинта отправки

Используйте асинхронный эндпоинт с очередью по умолчанию. Используйте прямую отправку только в тех случаях, когда приложению необходимо знать, принял ли WhatsApp отправку, прежде чем продолжить.

| Эндпоинт | Когда выбирать | Операционный эффект |
| - | - | - |
| `POST /whatsapp/messages` | Вы отправляете уведомления, кампании или другой стандартный исходящий трафик. | YCloud принимает запрос и отправляет его асинхронно. Ваше приложение может сглаживать пиковые нагрузки с помощью собственной очереди. |
| `POST /whatsapp/messages/sendDirectly` | Вы отправляете OTP или другое чувствительное ко времени сообщение, требующее синхронной отправки. | Запрос ожидает подтверждения отправки в WhatsApp Business API. Он не ожидает финальной доставки. |

Успешный ответ от любого из эндпоинтов не является подтверждением доставки. Сохраните возвращенный `id` сообщения и используйте события `whatsapp.message.updated`, чтобы узнать, находится ли сообщение в статусе `sent`, `failed`, `delivered` или `read`.

<Warning>
  Не переключайте весь высоконагруженный поток на `sendDirectly` с целью снижения задержки
  в очереди. Синхронные вызовы удерживают ресурсы приложения и все равно требуют
  асинхронной обработки статусов.
</Warning>

## Создание одной внутренней записи об отправке

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

Сохраняйте как минимум следующие данные:

| Поле | Назначение |
| - | - |
| Бизнес-ключ | Предотвращение создания двумя воркерами отдельных попыток для одного и того же бизнес-события. |
| `externalId` | Сопоставление данных YCloud с вашей внутренней записью и отчетами сверки. |
| YCloud `id` | Получение сообщения и сопоставление событий статуса. |
| `wamid` | Сопоставление с WhatsApp после отправки, когда это значение доступно. |
| Эндпоинт и попытка | Фиксация того, как было отправлено сообщение и сколько попыток на транспортном уровне произошло. |
| Текущий статус и метки времени | Формирование текущего операционного представления с сохранением истории событий. |

Используйте непрозрачный `externalId`, не содержащий содержимого сообщения или персональных данных. API рекомендует уникальное значение, но `externalId` является ссылочным полем. Оно не служит ключом идемпотентности на стороне сервера и не делает повторные запросы `POST` безопасными.

## Связывание ответа с Webhook статуса

В следующем примере используются одинаковые идентификаторы на протяжении всего процесса отправки.

### 1. Отправка сообщения

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
curl --request POST https://api.ycloud.com/v2/whatsapp/messages \
  --header "X-API-Key: $YCLOUD_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{
    "from": "+16315551111",
    "to": "+16315552222",
    "type": "template",
    "externalId": "order-ready-10001",
    "filterUnsubscribed": true,
    "filterBlocked": true,
    "template": {
      "name": "orders_pickup_ready_v2",
      "language": {
        "code": "en_US",
        "policy": "deterministic"
      }
    }
  }'
```

### 2. Сохранение принятого ответа

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "MESSAGE_ID",
  "wabaId": "WHATSAPP_BUSINESS_ACCOUNT_ID",
  "from": "+16315551111",
  "to": "+16315552222",
  "type": "template",
  "status": "accepted",
  "externalId": "order-ready-10001",
  "createTime": "2026-08-27T09:00:00.000Z"
}
```

Зафиксируйте `MESSAGE_ID`, `accepted` и время ответа в существующей внутренней записи. Не помечайте бизнес-уведомление как доставленное.

### 3. Применение последующих событий статуса

```json theme={"theme":{"light":"github-light","dark":"github-dark"}}
{
  "id": "evt_MESSAGE_STATUS_1",
  "type": "whatsapp.message.updated",
  "apiVersion": "v2",
  "createTime": "2026-08-27T09:00:02.000Z",
  "whatsappMessage": {
    "id": "MESSAGE_ID",
    "wamid": "wamid.BgNODYxN...",
    "status": "sent",
    "externalId": "order-ready-10001",
    "sendTime": "2026-08-27T09:00:01.000Z"
  }
}
```

Сопоставьте событие по `whatsappMessage.id`. Используйте `externalId` для бизнес-сверки и `wamid` для расследования на стороне провайдера.

## Построение модели сходящихся статусов

Стандартная последовательность: `accepted` → `sent` → `delivered` → `read`. Статус `failed` может возникнуть до или после обновления `sent`. Webhook-уведомления могут дублироваться, задерживаться или приходить не по порядку. Обновление `read` также может прийти без отдельного события `delivered`.

Обрабатывайте каждое событие следующим образом:

1. Проверяйте подпись Webhook по исходному (raw) телу запроса.
2. Надежно сохраняйте событие, используя `id` события в качестве ключа дедупликации.
3. Своевременно возвращайте ответ `2xx`, после чего обрабатывайте событие асинхронно.
4. Сопоставляйте `whatsappMessage.id` с внутренней записью об отправке.
5. Сохраняйте статус события и доступные метки времени сообщения. Сохраняйте исходные метаданные события, необходимые для аудита, но удаляйте ненужный контент сообщения.
6. Обновляйте текущее бизнес-представление, не отбрасывая противоречивые или более поздние данные. Рассматривайте `read` как подтверждение факта доставки, даже если отдельное событие `delivered` отсутствует.
7. Запрашивайте `GET /whatsapp/messages/{id}`, когда события конфликтуют, финальный статус задерживается сверх установленных целевых показателей обслуживания или если конвейер Webhook был недоступен.

Не реализуйте модель статусов как правило, принимающее только более высокий по рангу статус. Реальные обновления доставки не всегда поступают в таком порядке. Сохраняйте историю событий и предусмотрите возможность корректировки текущего представления в процессе сверки.

## Повторные попытки без создания дубликатов отправок

Классифицируйте ошибку перед повторной попыткой.

| Ошибка | Рекомендуемое действие |
| - | - |
| `400`, `404` или `422` | Исправьте запрос, ресурс, шаблон или бизнес-правило. Не повторяйте запрос без изменений. |
| `401` или `403` | Исправьте аутентификацию или доступ к аккаунту. Не повторяйте запрос с неизменными учетными данными. |
| `429` | Уменьшите параллелизм и повторите попытку с задержкой. |
| `5xx` | Повторите попытку при временной ошибке, используя экспоненциальную задержку (exponential backoff), джиттер (jitter) и ограничение максимального числа попыток. |
| Таймаут или потеря соединения | Считайте результат неоднозначным. Выполните сверку перед созданием новой отправки во всех случаях, когда запрос мог дойти до YCloud. |

Безопасная политика на уровне приложения может начинаться с небольшого количества попыток, экспоненциальных задержек, полного джиттера и максимального времени ожидания. Это элементы управления на стороне приложения, а не гарантии API. Направляйте исчерпавшие лимит попыток запросы в очередь на проверку, а не повторяйте их бесконечно.

Перед каждой повторной попыткой:

* Блокируйте или атомарно резервируйте внутренний бизнес-ключ.
* Проверьте, содержит ли запись уже `id` от YCloud или событие статуса.
* Не используйте новый `externalId`, чтобы скрыть более раннюю неоднозначную попытку.
* Останавливайте попытки после достижения настроенного лимита количества или времени жизни.
* Требуйте явного действия оператора перед повторным выполнением неоднозначной отправки.

## Выбор шаблонов и сессионных сообщений

Используйте одобренный шаблон сообщения при инициации бизнес-сообщения или отправке за пределами 24-часового окна обслуживания клиентов. Выбирайте категорию шаблона исходя из причины получения сообщения пользователем и храните его имя, язык и контракт переменных в конфигурации приложения.

Используйте текстовые, медиа, интерактивные сообщения, геолокацию, контакты или реакции только тогда, когда окно обслуживания клиентов открыто и данный тип контента разрешен. Определяйте окно по последнему сообщению от клиента. Не делайте вывод об открытом окне на основе вашего последнего исходящего сообщения.

См. раздел [Управление шаблонами WhatsApp](/ru/api-reference/guides/whatsapp-platform/manage-whatsapp-templates) для получения информации о версионировании шаблонов, этапах согласования, локалях и откате изменений.

## Эффективная работа с медиафайлами

* Проверяйте поддерживаемый MIME-тип и размер файла перед загрузкой. Не повторяйте попытку
  загрузки неподдерживаемого или превышающего лимиты файла без изменений.
* Загружайте файлы от имени того бизнес-номера телефона, с которого будет отправлено сообщение.
* Используйте возвращенный ID медиафайла повторно для регулярных отправок одного и того же утвержденного ресурса,
  пока он остается действительным. Загруженные медиафайлы хранятся 30 дней.
* Сохраняйте контрольную сумму ресурса, MIME-тип, ID медиафайла, отправителя и срок действия, чтобы
  воркеры не загружали один и тот же файл для каждого получателя заново.
* Выполняйте повторную загрузку после истечения срока действия или при изменении контекста отправителя.
* Используйте публичный URL-адрес, если схема сообщения требует ссылки, включая
  медиафайлы в заголовках интерактивных сообщений.
* Передавайте большие файлы потоком из хранилища, задавайте таймауты запросов и удаляйте временные
  локальные файлы после использования.

## Контроль согласия и минимизация данных

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

Для `POST /whatsapp/messages` задайте `filterUnsubscribed: true` и `filterBlocked: true`, если рабочий процесс должен соблюдать списки подавления YCloud. По умолчанию эти поля имеют значение `false`. Они не применяются к `sendDirectly`, поэтому процесс прямой отправки должен проверять статус подавления до вызова API.

Фильтры подавления — это окончательная мера безопасности, а не замена согласия. Храните только те идентификаторы и метаданные доставки, которые необходимы для указанной цели. Исключите ключи API, переменные шаблонов, тела сообщений и номера телефонов из общих журналов приложения. Настройте правила хранения и контроля доступа к записям сообщений и Webhook.

## Контроль пропускной способности пакетов

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

Применяйте противодавление (backpressure) при увеличении любого из следующих сигналов:

* ответы `429`
* задержка запросов и таймауты
* ответы `5xx`
* время нахождения в очереди или накопление повторных попыток
* задержка Webhook и необработанные сообщения со статусом `accepted`

Снижайте параллелизм, если отправка на стороне YCloud или последующая доставка замедляется. Возобновляйте отправку постепенно после восстановления. Не повторяйте отправку неудачных сообщений с частотой, превышающей исходную.

Отслеживайте как минимум объем запросов, процент принятых, частоту ошибок по HTTP-статусам и кодам ошибок, частоту статусов доставки, время перехода от `accepted` к каждому последующему статусу, глубину очереди, возраст самого старого элемента в очереди, количество повторных попыток, задержку Webhook, количество дедупликаций и расхождения при сверке. Настраивайте оповещения на устойчивые отклонения от нормального базового уровня, а не на единичные сбои сообщений.

## Распространенные антипаттерны

* Пометка сообщения как доставленного, когда API возвращает `accepted`.
* Использование `externalId` в качестве ключа идемпотентности YCloud.
* Повторная отправка каждого ответа, отличного от `2xx`, или таймаута без ограничения количества попыток.
* Использование `sendDirectly` для всего трафика.
* Предположение, что вебхуки уникальны, упорядочены или полны.
* Отправка сообщений в свободной форме за пределами окна обслуживания клиентов.
* Загрузка одного и того же медиафайла для каждого получателя.
* Использование фильтров подавления без фиксации согласия.
* Логирование ключей API, полных полезных нагрузок или избыточных персональных данных.
* Запуск пакетной обработки с неограниченным параллелизмом и без противодавления (backpressure).

## Чек-лист перед запуском в продакшн

* [ ] Выбор эндпоинта соответствует рабочей нагрузке и требованиям к задержке.
* [ ] Правило уникальности в базе данных защищает внутренний бизнес-ключ.
* [ ] Для `externalId`, `id` YCloud и `wamid` определены и задокументированы отдельные роли.
* [ ] Первоначальные ответы остаются неокончательными до получения подтверждения статуса.
* [ ] Протестированы подписи вебхуков, дедупликация событий, быстрое подтверждение получения и повторная обработка.
* [ ] Запланированная задача выборки сверяет задержанные или отсутствующие события.
* [ ] Ошибки, допускающие и не допускающие повторные попытки, имеют ограниченные сценарии обработки.
* [ ] Правила шаблонов и сессионных окон проверяются перед отправкой.
* [ ] Загрузка медиафайлов валидируется, файлы используются повторно, срок их действия отслеживается, а очистка выполняется безопасно.
* [ ] Проверены механизмы согласия, отписки, черных списков, хранения данных и логирования.
* [ ] Очереди пакетной обработки имеют ограничения параллелизма, противодавление, дашборды и алерты.
* [ ] Операторы могут приостанавливать отправку и проверять неоднозначные попытки без их автоматического повтора.

<CardGroup cols={2}>
  <Card title="Отправка сообщения WhatsApp" icon="whatsapp" href="/ru/api-reference/guides/whatsapp-platform/send-whatsapp-message">
    Ознакомьтесь с типами запросов, полями, примерами и данными ответов.
  </Card>

  <Card title="Настройка Webhook" icon="webhook" href="/ru/api-reference/guides/api-fundamentals/configure-webhooks">
    Проверяйте подписи и безопасно обрабатывайте повторные доставки событий.
  </Card>

  <Card title="Загрузка медиафайлов WhatsApp" icon="upload" href="/ru/api-reference/guides/whatsapp-platform/upload-whatsapp-media">
    Загружайте поддерживаемые медиафайлы и повторно используйте возвращенный media ID.
  </Card>

  <Card title="Обработка ошибок API" icon="triangle-exclamation" href="/ru/api-reference/guides/api-fundamentals/handle-errors">
    Парсите ответы с ошибками и применяйте ограниченные повторные попытки.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.