---
title: "Отправка сообщения WhatsApp через API: cURL, Node, Python, PHP"
description: "Как отправить сообщение WhatsApp через API: рабочие примеры на cURL, Node.js, Python и PHP для шаблонов и сессионных сообщений, отслеживание статусов и ошибки."
canonical: "https://omnichannels.ai/ru/blog/send-whatsapp-message-api-examples/"
language: "ru"
updated: "2026-10-16"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
category: "integration"
primaryQuery: "whatsapp api отправка сообщений"
keywords: ["пример whatsapp api curl", "отправка шаблона whatsapp node.js", "whatsapp api python", "whatsapp api php", "отправка сообщения whatsapp business api", "сессионное сообщение whatsapp api", "whatsapp api multipart form-data"]
published: "2026-10-16"
author: "OmniChannels.ai Editorial Team"
reviewer: "BroadNet Messaging Solutions Team"
readingMinutes: 10
answer: "В API OmniChannels.ai каждое сообщение WhatsApp отправляется через один эндпоинт, POST https://api.broadnet.me/whatsapp/message/sendbulk, в виде multipart form data с заголовком Authorization: Bearer. Поле messageType выбирает содержимое: TEMPLATE для одобренных шаблонов, которые нужны, чтобы начать диалог или написать вне 24-часового окна, и TEXT, IMAGE или INTERACTIVE для ответов внутри окна."
takeaways: ["Все сообщения WhatsApp отправляются через POST /whatsapp/message/sendbulk; messageType (TEMPLATE, TEXT, IMAGE, INTERACTIVE и другие) определяет, какие поля обязательны.", "Запрос имеет формат multipart/form-data, а не JSON, поэтому в Python нужен параметр files=, а в PHP — тело в виде массива, чтобы не произошло url-кодирования.", "Вне 24-часового окна обслуживания клиента можно отправить только одобренный шаблон; внутри окна можно отправлять свободный текст, медиа и интерактивные сообщения.", "Вызов ставит сообщения в очередь и сразу возвращает batchId; статусы по каждому получателю приходят на ваш вебхук и доступны через эндпоинт bulk-insights.", "API не принимает ключ идемпотентности, поэтому записывайте каждую отправку до вызова и после тайм-аута проверяйте статус, а не отправляйте повторно."]
faq: 
  - q: "Отправлять сообщения WhatsApp как JSON или как form data?"
    a: "Как form data. Эндпоинт отправки WhatsApp POST /whatsapp/message/sendbulk принимает multipart/form-data, где каждое поле — отдельная часть формы. Одиночная отправка SMS использует JSON, и это частый источник путаницы. В Python передавайте поля через files=, а не data=, а в PHP передавайте массив в качестве тела, чтобы cURL сформировал multipart."
  - q: "Можно ли отправить сообщение WhatsApp без шаблона?"
    a: "Только внутри окна обслуживания клиента. Когда клиент пишет вам, открывается 24-часовое окно, и вы можете отвечать текстом, медиа или интерактивными сообщениями. Вне его или чтобы начать диалог, нужно отправить одобренный шаблон. API применяет правила Meta, и свободная отправка при закрытом окне завершится ошибкой."
  - q: "Как узнать, доставлено ли сообщение?"
    a: "Вызов отправки лишь подтверждает, что сообщения поставлены в очередь, и возвращает batchId. Статусы по получателям проходят через SUBMITTED, SENT, DELIVERED и READ либо завершаются как FAILED или REJECTED. Они отправляются на ваш вебхук, а также их можно читать по пакету через эндпоинт bulk-insights."
  - q: "Можно ли отправить нескольким получателям одним запросом?"
    a: "Да. destinationNo принимает несколько номеров через запятую, точку с запятой или перевод строки, а destinationFiles принимает файл TXT, CSV или XLSX. Для шаблона с разными переменными для каждого получателя загрузите персонализированный файл с одной строкой на получателя. Задайте allowDuplicate значение false, чтобы удалить повторяющиеся номера."
  - q: "Есть ли ключ идемпотентности для защиты от повторных отправок?"
    a: "Нет. API не принимает ключ идемпотентности. Если запрос завершился по тайм-ауту, со стороны клиента нельзя понять, был ли он принят. Записывайте каждую отправку в свою базу до вызова, сохраняйте возвращённый batchId и проверяйте статус или список пакетов перед любым повтором."
  - q: "Нужно ли согласие (opt-in) перед отправкой?"
    a: "Да. Политика Meta требует, чтобы каждый получатель дал согласие на получение сообщений от вашей компании, а шаблоны должны быть одобрены до использования. API не проверяет согласие за вас. Получайте согласие в источнике, сохраняйте подтверждение и исключайте отписавшихся."
sources: 
  - title: "WhatsApp Business Messaging Policy"
    url: "https://business.whatsapp.com/policy"
  - title: "Pricing on the WhatsApp Business Platform — Meta for Developers"
    url: "https://developers.facebook.com/documentation/business-messaging/whatsapp/pricing"
  - title: "RFC 7578: Returning Values from Forms: multipart/form-data"
    url: "https://www.rfc-editor.org/rfc/rfc7578"
---

# Отправка сообщения WhatsApp через API: cURL, Node, Python, PHP

Canonical: https://omnichannels.ai/ru/blog/send-whatsapp-message-api-examples/
Language: ru
Publisher: OmniChannels.ai by BroadNet Technologies

Это руководство для разработчиков, которые встраивают отправку WhatsApp в приложение. В нём показаны рабочие запросы на cURL, Node.js, Python и PHP, объясняется разница между шаблонными и сессионными сообщениями, а также рассматриваются отслеживание и ошибки. Все эндпоинты и поля взяты из нашего [справочника WhatsApp API](/developers/whatsapp/) и спецификации OpenAPI.

## Как отправить сообщение WhatsApp через API?

Вы выполняете один аутентифицированный `POST` на `https://api.broadnet.me/whatsapp/message/sendbulk` с полями формы. Поле `messageType` выбирает вид сообщения, а ответ подтверждает, что сообщения поставлены в очередь.

| Параметр | Значение |
|---|---|
| Базовый URL | `https://api.broadnet.me` (без префикса `/v1`) |
| Эндпоинт | `POST /whatsapp/message/sendbulk` |
| Аутентификация | `Authorization: Bearer $BROADNET_TOKEN` |
| Тип содержимого | `multipart/form-data` (HTTP-клиент задаёт его автоматически) |
| Ответ | JSON-сводка по пакету с `batchId` |

Тестовые учётные данные выдаются после краткого запроса доступа, а тестовые отправки идут на ваши собственные подтверждённые номера. См. [быстрый старт](/developers/quickstart/) и страницы об аутентификации. Храните токен только на своём сервере.

## Шаблон или сессионное сообщение: что отправлять?

Отправляйте шаблон, чтобы начать диалог или написать вне окна, и сессионное сообщение, если клиент писал вам в последние 24 часа. Это правило задаёт Meta, а не мы.

| | Шаблонное сообщение | Сессионное сообщение |
|---|---|---|
| `messageType` | `TEMPLATE` | `TEXT`, `IMAGE`, `VIDEO`, `AUDIO`, `DOCUMENT`, `INTERACTIVE` и другие |
| Когда разрешено | В любое время после одобрения шаблона | Только пока открыто окно обслуживания клиента |
| Нужно одобрение | Да, со стороны Meta | Нет |
| Типичное применение | Обновления по заказам, OTP, напоминания, рассылки | Ответы поддержки, ответы на вопросы |

Meta берёт плату за каждое доставленное сообщение в зависимости от категории, а её правила для сервисных сообщений и utility-шаблонов изменились 1 октября 2026 года. Механику описывает наше [руководство об окне обслуживания](/ru/blog/whatsapp-24-hour-customer-service-window/), а стоимость — наша [страница цен](/ru/whatsapp-pricing/) и [калькулятор](/ru/tools/whatsapp-pricing-calculator/).

## Как отправить одобренный шаблон?

Задайте `messageType=TEMPLATE`, укажите шаблон и код его языка и передайте значения переменных. Чтобы начать новый пакет, задайте `batchId=0`.

```bash
curl -X POST https://api.broadnet.me/whatsapp/message/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F batchId=0 \
  -F campaignName=order-updates \
  -F destinationNo=971500000000 \
  -F messageType=TEMPLATE \
  -F templateName=order_update \
  -F templateLanguage=en_US \
  -F bodyTemplateVariables=INV-400
```

```js
// Node.js 18+ (встроенные fetch и FormData)
const form = new FormData();
form.append("batchId", "0");
form.append("campaignName", "order-updates");
form.append("destinationNo", "971500000000");
form.append("messageType", "TEMPLATE");
form.append("templateName", "order_update");
form.append("templateLanguage", "en_US");
form.append("bodyTemplateVariables", "INV-400");

const res = await fetch("https://api.broadnet.me/whatsapp/message/sendbulk", {
  method: "POST",
  headers: { Authorization: `Bearer ${process.env.BROADNET_TOKEN}` }, // fetch сам задаёт границу multipart
  body: form,
});
console.log(await res.json());
```

```python
import os
import requests

fields = {
    "batchId": "0",
    "campaignName": "order-updates",
    "destinationNo": "971500000000",
    "messageType": "TEMPLATE",
    "templateName": "order_update",
    "templateLanguage": "en_US",
    "bodyTemplateVariables": "INV-400",
}
# Отправляйте каждое поле как часть multipart (files=), а не с url-кодированием (data=).
r = requests.post(
    "https://api.broadnet.me/whatsapp/message/sendbulk",
    headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
    files={k: (None, v) for k, v in fields.items()},
    timeout=30,
)
print(r.json())
```

```php
<?php
$ch = curl_init("https://api.broadnet.me/whatsapp/message/sendbulk");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => ["Authorization: Bearer " . getenv("BROADNET_TOKEN")],
    // Массив (а не строка) заставляет cURL отправить multipart/form-data.
    CURLOPT_POSTFIELDS => [
        "batchId" => "0",
        "campaignName" => "order-updates",
        "destinationNo" => "971500000000",
        "messageType" => "TEMPLATE",
        "templateName" => "order_update",
        "templateLanguage" => "en_US",
        "bodyTemplateVariables" => "INV-400",
    ],
]);
echo curl_exec($ch);
curl_close($ch);
```

Номер назначения — код страны плюс номер, только цифры. Вызов сразу возвращает сводку по пакету:

```json
{
  "totalFiles": 1,
  "totalSuccess": 1,
  "totalFailed": 0,
  "totalDuplicates": 0,
  "batchId": "2609091405000000001",
  "fileResults": [
    {
      "fileName": "direct",
      "totalRecords": 1,
      "successCount": 1,
      "failedRecipients": [],
      "duplicateRecipients": []
    }
  ],
  "message": "Messages queued for delivery"
}
```

Сохраните `batchId` рядом со своей записью. «В очереди» не означает «доставлено».

## Какие поля запроса важнее всего?

Какие поля обязательны, зависит от `messageType`. Вот самые распространённые.

| Поле | Обязательно | Описание |
|---|---|---|
| `messageType` | Да | `TEXT`, `IMAGE`, `VIDEO`, `AUDIO`, `DOCUMENT`, `STICKER`, `LOCATION`, `CONTACTS`, `TEMPLATE`, `INTERACTIVE`, `REACTION` или `FLOW` |
| `destinationNo` или `destinationFiles` | Одно из двух | Номера через запятую, точку с запятой или перевод строки; либо файл TXT, CSV или XLSX |
| `batchId` | Нет | `0` начинает новый пакет |
| `campaignName` | Нет | Ваша метка для отчётности |
| `allowDuplicate` | Нет | `false` удаляет повторяющихся получателей |
| `templateName`, `templateLanguage` | Для `TEMPLATE` | Название одобренного шаблона и код языка, например `en_US` или `ar` |
| `bodyTemplateVariables` | По шаблону | Значение переменной основного текста; именованные параметры передаются как JSON |
| `buttonsTemplateVariable` | По шаблону | Динамическое значение кнопки: суффикс URL, код купона или OTP-код |
| `content` | Для `TEXT` | Текст сообщения до 4 096 символов либо подпись к медиа |
| `mediaUrl` | По типу | Публичный HTTPS URL медиафайла |
| `interactivePayload` | Для `INTERACTIVE` | Интерактивный объект Meta в виде JSON-строки |

Для планирования используются `scheduled`, `scheduleTime` и `gmt`, а `delay` ограничивает скорость доставки. Полный список — в [справочнике WhatsApp API](/developers/whatsapp/).

## Как отправить шаблон с кнопкой или OTP?

Передайте значение кнопки в `buttonsTemplateVariable`. Для шаблона аутентификации с кнопкой копирования кода передайте код и в поле основного текста, и в поле кнопки.

```bash
curl -X POST https://api.broadnet.me/whatsapp/message/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F batchId=0 \
  -F destinationNo=971500000000 \
  -F messageType=TEMPLATE \
  -F templateName=login_code \
  -F templateLanguage=en_US \
  -F bodyTemplateVariables=482913 \
  -F buttonsTemplateVariable=482913
```

Здесь `login_code` — заглушка для вашего собственного одобренного шаблона аутентификации. Для нескольких кнопок `buttonsTemplateVariable` принимает JSON-массив. Генерируйте код на сервере, храните его в виде хеша со сроком действия и никогда не логируйте. Доставку в режимах one-tap, zero-tap и copy-code описывает наше [руководство по OTP](/ru/blog/otp-authentication-messages-guide/).

## Как ответить внутри окна обслуживания клиента?

Используйте тип сессионного сообщения. Для простого текстового ответа нужны `messageType=TEXT` и `content`.

```bash
curl -X POST https://api.broadnet.me/whatsapp/message/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F batchId=0 \
  -F destinationNo=971500000000 \
  -F messageType=TEXT \
  -F campaignName=support \
  -F "content=Your order has shipped. Reply here if you need anything."
```

Для кнопок ответа отправьте `messageType=INTERACTIVE` и `interactivePayload`, соответствующий формату интерактивных сообщений Meta.

```bash
curl -X POST https://api.broadnet.me/whatsapp/message/sendbulk \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -F batchId=0 \
  -F destinationNo=971500000000 \
  -F messageType=INTERACTIVE \
  -F campaignName=support \
  -F 'interactivePayload={"type":"button","body":{"text":"Confirm your delivery slot?"},"action":{"buttons":[{"type":"reply","reply":{"id":"slot_ok","title":"Confirm"}},{"type":"reply","reply":{"id":"slot_change","title":"Change"}}]}}'
```

Чтобы отметить входящее сообщение прочитанным и при желании показать индикатор набора текста, вызовите `POST /whatsapp/message/read` с JSON:

```bash
curl -X POST https://api.broadnet.me/whatsapp/message/read \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "messageId": "wamid.HBgMOTcxNTAwMDAwMDAwFQIAEhgg", "typing": true }'
```

Рекомендации по оформлению см. в нашем руководстве по интерактивным сообщениям.

## Как отслеживать доставку?

Статусы отправляются на вебхук, настроенный в вашем аккаунте, и их также можно читать по пакету. Каждый получатель проходит через `SUBMITTED`, `SENT`, `DELIVERED` и `READ` либо завершается как `FAILED` или `REJECTED` с указанием причины.

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

`batch_Id` обязателен; `status`, `destination`, `search`, `page` и `size` необязательны, а `page` нумеруется с нуля. Используйте опрос как страховку на случай пропущенных событий и создайте приёмник по описанию в нашем [руководстве по вебхукам](/ru/blog/whatsapp-webhooks-guide/). Пакеты также можно приостанавливать, возобновлять и прерывать с помощью эндпоинтов пакетов из справочника.

## Какие ошибки нужно обрабатывать?

Сначала читайте HTTP-статус, затем тело ошибки. API возвращает ошибки в JSON-теле из пяти полей, а специфические для WhatsApp сбои могут приходить от Meta.

| Статус | Значение | Действие |
|---|---|---|
| `400` | Ошибка валидации, например отсутствует поле, обязательное для типа, или неверный адресат | Исправьте запрос; не повторяйте без изменений |
| `401` / `403` | Токен отсутствует или недействителен, либо операция не разрешена | Исправьте токен или попросите нас включить операцию |
| `404` | Шаблон или отправитель не найден | Проверьте название и язык шаблона |
| `413` | Загруженный файл слишком большой | Уменьшите файл |
| `429` | Превышен лимит запросов | Подождите значение `Retry-After` |
| `502` | Meta отклонила вызов; в `message` указан код и текст ошибки Meta | Прочитайте его; повторяйте только при временной ошибке |
| `500`, `503`, `504` | Проблема на сервере или у вышестоящего узла | Повторяйте с экспоненциальной отсрочкой и jitter |

Распространённые коды Meta объясняет наше руководство по кодам ошибок. Поскольку ключа идемпотентности нет, выполняйте шаги защиты от дублей из раздела [ошибки и лимиты](/developers/errors-and-limits/): сначала запишите pending-запись, сохраните возвращённый `batchId`, а после тайм-аута проверьте статус, прежде чем отправлять снова.

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

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

1. Сервис заказов записывает строку с ключом `order-8842-shipped` и статусом `pending`.
2. Он вызывает `sendbulk` с шаблоном и номером заказа в `bodyTemplateVariables`.
3. При ответе `200` он сохраняет `batchId` и отмечает строку как `accepted`.
4. Обработчик вебхука обновляет строку до `DELIVERED` или `READ`, либо `FAILED` с указанием причины.
5. Если клиент отвечает, инструмент поддержки использует сессионное сообщение `TEXT` внутри окна.
6. Ночное задание читает `bulk-insights` по вчерашним пакетам и сверяет недостающие статусы.

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

- **Отправка JSON.** Эндпоинт отправки WhatsApp принимает multipart; `Content-Type: application/json` не сработает.
- **`data=` в Python** вместо `files=`, из-за чего форма url-кодируется.
- **Свободный текст вне окна,** который завершается ошибкой. Используйте шаблон.
- **Неверный код языка,** например `en` вместо `en_US` у шаблона.
- **Принятие `200` за доставку.** Он означает «в очереди».
- **Слепые повторы** после тайм-аута, из-за которых клиенту можно написать дважды.
- **Токен в клиентском коде.** Вызывайте API только из бэкенда.
- **Ограничения:** детали payload зависят от шаблона. Структуру переменных для вашей первой персонализированной рассылки подтвердите у нашей команды.

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

BroadNet — официальный Meta Business Solution Provider, а подключение к WhatsApp Business API проходит через Meta Embedded Signup; наша команда вместе с вами готовит регистрацию, а одобрения остаются за Meta. REST API документирован спецификацией OpenAPI 3.1 и TypeScript SDK `@broadnet/cpaas-sdk`, а статусы доставки приводятся к единому виду во всех каналах. Начните с [документации WhatsApp API](/developers/whatsapp/) или [быстрого старта](/developers/quickstart/).
