API сообщений
API отправки сообщений
Отправляйте текст, изображение или документ WhatsApp на один номер телефона со своего подключённого номера WhatsApp. Подходит для подтверждений заказов, напоминаний об оплате, уведомлений и ответов службы поддержки.
https://wbiztool.com/api/v1/send_msg/Тело запроса: JSON, поля формы или multipart/form-data при загрузке файла
Сообщение ставится в очередь и отправляется с вашего номера WhatsApp в течение нескольких мгновений. В ответе вы получаете msg_id, по которому можно проверить его статус.
Быстрый пример#
curl -X POST https://wbiztool.com/api/v1/send_msg/ \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"whatsapp_client": 678,
"msg_type": 0,
"country_code": "91",
"phone": "9876543210",
"msg": "Hi Aman, your order #4821 has shipped and will arrive on Thursday."
}'import requests
response = requests.post(
"https://wbiztool.com/api/v1/send_msg/",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"whatsapp_client": 678,
"msg_type": 0,
"country_code": "91",
"phone": "9876543210",
"msg": "Hi Aman, your order #4821 has shipped and will arrive on Thursday.",
},
timeout=60,
)
result = response.json() # read the body even when the HTTP code is 400
if result.get("status") == 1:
print("Queued with msg_id", result["msg_id"])
else:
print("Failed:", result.get("message"))// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v1/send_msg/", {
method: "POST",
headers: { "Authorization": "Bearer YOUR_API_KEY", "Content-Type": "application/json" },
body: JSON.stringify({
whatsapp_client: 678,
msg_type: 0,
country_code: "91",
phone: "9876543210",
msg: "Hi Aman, your order #4821 has shipped and will arrive on Thursday.",
}),
});
const result = await response.json(); // read the body even when the HTTP code is 400
if (result.status === 1) {
console.log("Queued with msg_id", result.msg_id);
} else {
console.error("Failed:", result.message);
}<?php
$payload = [
'whatsapp_client' => 678,
'msg_type' => 0,
'country_code' => '91',
'phone' => '9876543210',
'msg' => 'Hi Aman, your order #4821 has shipped and will arrive on Thursday.',
];
$ch = curl_init('https://wbiztool.com/api/v1/send_msg/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer YOUR_API_KEY', 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode($payload),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 60,
]);
$result = json_decode(curl_exec($ch), true);
curl_close($ch);
if (($result['status'] ?? 0) === 1) {
echo 'Queued with msg_id ' . $result['msg_id'];
} else {
echo 'Failed: ' . ($result['message'] ?? 'no response');
}Замените YOUR_API_KEY и 678 своим ключом и ID номера. Где их найти, описано в разделе Аутентификация. Ключ передаётся в заголовке Authorization: Bearer (рекомендуется); client_id и api_key в теле запроса, в виде JSON или полей формы, тоже работают: в примерах ниже используются именно они.
Параметры запроса#
Аутентификация
AuthorizationheaderРекомендуетсяBearer YOUR_API_KEY: ваш API-ключ со страницы Настройки → API-ключи. С заголовкомclient_idиapi_keyможно не указывать в теле запроса; если ключ передан в обоих местах, используется действительный ключ из заголовка. См. Передача ключа в заголовке.client_idintegerБез заголовка AuthorizationВаш API Client ID из раздела Настройки → API-ключи. С заголовком необязателен; если вы его передаёте, он должен принадлежать рабочему пространству ключа.
api_keystringБез заголовка AuthorizationВаш API-ключ с той же страницы, если вы не передаёте его в заголовке.
whatsapp_clientintegerОбязателен, если у вас больше одного номераID номера WhatsApp или аккаунта Telegram, с которого отправляется сообщение, со страницы настроек WhatsApp. Если вы его не передадите, используется единственный подключённый номер, причём WhatsApp в приоритете: один подключённый номер WhatsApp используется, даже если подключён ещё и аккаунт Telegram, а аккаунт Telegram — только когда не подключено ни одного номера WhatsApp. Для
@usernameиспользуется единственный подключённый аккаунт Telegram.
Получатель и сообщение
phonestringобязательноНомер WhatsApp получателя. Пробелы,
+,-,., скобки и00в начале удаляются автоматически, поэтому+91 98765-43210подойдёт. Значения из таблиц, например919876543210.0и9.19876543210E+11, читаются как их цифры, а округлённое, например9.19877E+11, отклоняется, потому что в нём не хватает цифр. Передайте номер либо с кодом страны (919876543210), либо без него (9876543210) вместе сcountry_code. Местный номер с ведущим0тоже работает:09876543210сcountry_code91уходит на919876543210, а0612345678с39(Италия, где0— часть номера) — на390612345678. Номер, написанный с+или00, уже содержит свой код страны:country_codeк нему не добавляется, а(0)в скобках после кода удаляется, поэтому+44 (0)20 7946 0018уходит на442079460018. С аккаунта Telegram вphoneможно также передать@username, ссылкуt.me/usernameилиtg:<id>.country_codestringнеобязательноТелефонный код страны без
+, например91для Индии или1для США. Он добавляется передphone, если номер ещё не начинается с него и не написан с+или00. Исключение: с кодом91к 10-значному номеру префикс добавляется всегда. С другими кодами местный номер, который начинается с тех же цифр, префикс не получает, поэтому передавайте такой номер уже с кодом страны.msg_typeintegerнеобязательно0— текст (по умолчанию),1— изображение,2— файл или документ.msgstringОбязателен, если msg_type равен 0Текст сообщения, до 3000 символов. Для изображений и файлов это подпись, она может быть пустой. Форматирование WhatsApp работает:
*bold*,_italic_,~strikethrough~. В качестве псевдонима принимаетсяmessage.
Изображения и файлы
img_urlstringОбязателен, если msg_type равен 1 и файл не загружаетсяПубличный URL изображения (
httpилиhttps).file_urlstringОбязателен, если msg_type равен 2 и файл не загружаетсяПубличный URL (
httpилиhttps), по которому файл можно скачать напрямую.filefileнеобязательноЗагрузите изображение или файл вместо указания URL. Отправьте запрос как
multipart/form-dataс полемfile.file_namestringнеобязательноИмя файла, которое увидит получатель, например
invoice-4821.pdf. От расширения зависит, как будет отправлен файл, поэтому обязательно укажите его. Отправляется в нижнем регистре, символы вроде& : ? * $ ;заменяются на_, а длина обрезается до 150 символов. Если параметр не передан, имя берётся из URL или загруженного файла.
Параметры доставки
expire_after_secondsintegerнеобязательноПометить сообщение как просроченное (статус
4), если оно не было отправлено в течение указанного числа секунд, например3600— один час. Полезно для сообщений, привязанных ко времени, например ожидаемого времени доставки. Это делает фоновая задача не раньше чем через 30 секунд после срока, поэтому не полагайтесь на неё для сроков меньше минуты.webhookstringнеобязательноURL, на который приходит
POST, когда сообщение отправлено, не удалось его отправить, оно отменено или срок его действия истёк. См. раздел Webhook.
Отправка изображений и файлов#
Ограничения на загрузку по img_url и file_url:
- URL должен быть публичным:
httpилиhttps, доступный из интернета. Выполняется до 5 перенаправлений, и каждое из них тоже должно вести на публичный адрес. - Файлы по ссылке могут быть размером до 100 МБ. Сервер должен начать отвечать в течение 45 секунд и не зависать дольше этого времени.
- Файл скачивается в момент вызова API, поэтому нерабочая ссылка сразу приводит к ошибке
Invalid file url.
Файлы, отправленные с msg_type 2, сохраняют эти расширения:
| Категория | Расширения |
|---|---|
| Изображения | .jpg, .jpeg, .jpe, .png, .gif, .webp, .bmp |
| Документы | .pdf, .doc, .docx, .docm, .xls, .xlsx, .xlsm, .xlsb, .ppt, .pptx, .pptm, .txt, .csv |
| Аудио | .mp3, .mpga, .m4a, .aac, .wav, .ogg, .oga |
| Видео | .mp4, .mov, .avi, .webm |
| Архивы | .zip, .rar |
Эти проверки выполняются при отправке сообщения, а не при вызове API, поэтому такие ошибки видны только в API статуса сообщений и в webhook:
| Проблема | error в статусе сообщения |
|---|---|
Изображение (msg_type 1) больше 16 МБ | File exceeds WhatsApp size limit (16MB max) |
Видео (.mp4, .webm) больше 64 МБ, в том числе отправленное как изображение (msg_type 1) | File exceeds WhatsApp size limit (64MB max) |
Любой другой файл (msg_type 2) больше 100 МБ | File exceeds WhatsApp size limit (100MB max) |
| Пустой файл (0 байт) | The file is empty |
Файл .wav или .ogg, отправленный как изображение (msg_type 1) | File type not supported |
Аудио WAV и OGG нельзя отправить как изображение (msg_type 1). Отправленные как файл (msg_type 2), они приходят как документ под своим именем, например recording.wav. Файлы .mp3, .mpga, .m4a и .aac приходят как аудио, которое воспроизводится в чате, а msg идёт следом отдельным текстовым сообщением (у аудио нет подписи).
curl -X POST https://wbiztool.com/api/v1/send_msg/ \
-H "Content-Type: application/json" \
-d '{
"client_id": 12345,
"api_key": "YOUR_API_KEY",
"whatsapp_client": 678,
"msg_type": 1,
"country_code": "91",
"phone": "9876543210",
"img_url": "https://example.com/offers/diwali-sale.jpg",
"msg": "Our Diwali sale starts today 🎉"
}'import requests
response = requests.post(
"https://wbiztool.com/api/v1/send_msg/",
json={
"client_id": 12345,
"api_key": "YOUR_API_KEY",
"whatsapp_client": 678,
"msg_type": 1,
"country_code": "91",
"phone": "9876543210",
"img_url": "https://example.com/offers/diwali-sale.jpg",
"msg": "Our Diwali sale starts today 🎉",
},
timeout=60,
)
print(response.json())// Node.js 18+ (built-in fetch). Save as .mjs to use top-level await.
const response = await fetch("https://wbiztool.com/api/v1/send_msg/", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
client_id: 12345,
api_key: "YOUR_API_KEY",
whatsapp_client: 678,
msg_type: 1,
country_code: "91",
phone: "9876543210",
img_url: "https://example.com/offers/diwali-sale.jpg",
msg: "Our Diwali sale starts today 🎉",
}),
});
console.log(await response.json());<?php
$ch = curl_init('https://wbiztool.com/api/v1/send_msg/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'client_id' => 12345,
'api_key' => 'YOUR_API_KEY',
'whatsapp_client' => 678,
'msg_type' => 1,
'country_code' => '91',
'phone' => '9876543210',
'img_url' => 'https://example.com/offers/diwali-sale.jpg',
'msg' => 'Our Diwali sale starts today 🎉',
]),
CURLOPT_RETURNTRANSFER => true,
]);
echo curl_exec($ch);
curl_close($ch);curl -X POST https://wbiztool.com/api/v1/send_msg/ \
-F client_id=12345 \
-F api_key=YOUR_API_KEY \
-F whatsapp_client=678 \
-F msg_type=2 \
-F country_code=91 \
-F phone=9876543210 \
-F "msg=Your invoice for order #4821 is attached." \
-F file_name=invoice-4821.pdf \
-F file=@./invoice-4821.pdfimport requests
with open("invoice-4821.pdf", "rb") as f:
response = requests.post(
"https://wbiztool.com/api/v1/send_msg/",
data={
"client_id": 12345,
"api_key": "YOUR_API_KEY",
"whatsapp_client": 678,
"msg_type": 2,
"country_code": "91",
"phone": "9876543210",
"msg": "Your invoice for order #4821 is attached.",
"file_name": "invoice-4821.pdf",
},
files={"file": f},
timeout=120,
)
print(response.json())// Node.js 20+ (built-in fetch, FormData and fs.openAsBlob). Save as .mjs to use top-level await.
import { openAsBlob } from "node:fs";
const form = new FormData();
form.append("client_id", "12345");
form.append("api_key", "YOUR_API_KEY");
form.append("whatsapp_client", "678");
form.append("msg_type", "2");
form.append("country_code", "91");
form.append("phone", "9876543210");
form.append("msg", "Your invoice for order #4821 is attached.");
form.append("file_name", "invoice-4821.pdf");
form.append("file", await openAsBlob("./invoice-4821.pdf"), "invoice-4821.pdf");
// Don't set Content-Type yourself; fetch adds the multipart boundary.
const response = await fetch("https://wbiztool.com/api/v1/send_msg/", { method: "POST", body: form });
console.log(await response.json());<?php
$ch = curl_init('https://wbiztool.com/api/v1/send_msg/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
// An array body (not json_encode) makes cURL send multipart/form-data.
CURLOPT_POSTFIELDS => [
'client_id' => 12345,
'api_key' => 'YOUR_API_KEY',
'whatsapp_client' => 678,
'msg_type' => 2,
'country_code' => '91',
'phone' => '9876543210',
'msg' => 'Your invoice for order #4821 is attached.',
'file_name' => 'invoice-4821.pdf',
'file' => new CURLFile('/path/to/invoice-4821.pdf', 'application/pdf', 'invoice-4821.pdf'),
],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 120,
]);
echo curl_exec($ch);
curl_close($ch);Использование официальных клиентов#
Клиенты для Python и Node.js вызывают этот endpoint за вас.
from wbiztool_client import WbizToolClient
client = WbizToolClient(api_key="YOUR_API_KEY", client_id="12345")
result = client.send_message(
phone="9876543210",
country_code="91",
msg="Hi Aman, your order #4821 has shipped.",
whatsapp_client=678,
)
print(result)При ошибках выбрасывается requests.HTTPError. Причину можно прочитать через e.response.json()["message"].
const { WbizToolClient } = require("wbiztool-client");
const client = new WbizToolClient({
clientId: 12345,
apiKey: "YOUR_API_KEY",
whatsappClient: 678,
});
(async () => {
// Errors throw, with the API's response in the error message.
const result = await client.sendMessage({
phone: "9876543210",
countryCode: "91",
message: "Hi Aman, your order #4821 has shipped.",
});
console.log(result);
})().catch(console.error);Ответ#
Успешный запрос возвращает HTTP 200:
{
"status": 1,
"message": "Created",
"msg_id": 9817263
}
| Поле | Тип | Описание |
|---|---|---|
status | integer | 1, если сообщение поставлено в очередь, 0, если запрос не выполнен. |
message | string | Created при успехе, иначе текст ошибки. |
msg_id | integer | ID сообщения в очереди. Сохраните его, чтобы позже проверить статус. Присутствует только при успехе. |
"status": 1 означает, что сообщение поставлено в очередь, а не что оно уже дошло до получателя. Чтобы убедиться, что оно отправлено, используйте webhook или Статус сообщения.
Ошибки#
Ошибки возвращаются с HTTP 400 и status, равным 0 (у Account Disabled нет поля status):
{ "status": 0, "message": "Msg cant be null" }
| Сообщение | Как исправить |
|---|---|
Auth Error - Please send correct API key and Client id | Передайте непустой api_key. |
Invalid client id. | Передайте client_id числом. |
Auth Error: invalid api key | Проверьте, что ключ существует, не удалён и принадлежит этому client_id. |
Either phone or group_name parameter is required | Добавьте phone. |
Please provide either phone OR group_name, not both | Удалите один из параметров. |
Invalid phone number | phone должен быть номером из 6–17 цифр. Буквы и другие символы не допускаются, как и округлённое значение из таблицы, например 9.19877E+11. |
Invalid Contact Number "…" | Вместе с кодом страны номер должен содержать от 7 до 15 цифр. |
Msg cant be null | Для текстовых сообщений (msg_type 0) нужен msg. |
Message length is too long | Длина msg не должна превышать 3000 символов. |
Image Url Can't be null | Для msg_type 1 передайте img_url или загрузите file. |
File Url Can't be null | Для msg_type 2 передайте file_url или загрузите file. |
Invalid file url, Can't download / Invalid file url | URL не публичный, истекло время ожидания или файл больше 100 МБ. |
Invalid whatsapp client | Этого ID whatsapp_client нет в вашем рабочем пространстве. |
Invalid whatsapp client id. | Передайте whatsapp_client. Он обязателен, если в вашем рабочем пространстве больше одного подключённого номера. |
Telegram usernames can only be sent to from a Telegram account: pass its id as whatsapp_client | Для @username, ссылки t.me или tg:<id> в phone нужен аккаунт Telegram в whatsapp_client. |
Not enough credits | Рабочее пространство на бесплатном тарифе, и у него не осталось сообщений: платные тарифы отправляют безлимитные сообщения. См. Когда закончились сообщения. |
Daily limit reached: a number can send 1,000 messages in 24 hours (fair use). Send the rest tomorrow. (HTTP 429, "code": "daily_limit_reached") | Этот номер принял 1 000 сообщений за последние 24 часа (честное использование). Ответ всё равно содержит msg_id отклонённого сообщения, которое отображается как неудачное. Отправьте остальное позже или с другого номера. |
Demo Account can not access apis | Используйте обычный аккаунт. |
Account Disabled | Ваш аккаунт отключён. Свяжитесь с поддержкой. |
Invalid JSON format: … | Тело JSON некорректно — часто из-за лишней запятой в конце или неэкранированного перевода строки в msg. Для новой строки используйте \n. |
Сообщение, поставленное в очередь, всё ещё может не отправиться, например с ошибкой File exceeds WhatsApp size limit (…). Такие ошибки никогда не появляются в этом ответе. См. Отправка изображений и файлов и проверяйте API статуса сообщений.
Webhook#
Если вы передали webhook, WbizTool отправляет POST на этот URL, когда сообщение отправлено или не удалось его отправить, а также когда оно отменено или срок его действия истёк до отправки. Тело запроса передаётся в виде полей формы (application/x-www-form-urlencoded), а не JSON:
msg_id=9817263&status=SENT
| Поле | Значения |
|---|---|
msg_id | msg_id, полученный при отправке сообщения. |
status | SENT, FAILED, CANCELLED (отменено до отправки: через API отмены сообщений, в панели управления или потому, что был удалён его номер WhatsApp или кампания) или EXPIRED (не отправлено до истечения expire_after_seconds) |
Каждый вебхук подписан: заголовки WbizTool-Timestamp и WbizTool-Signature (v1= и HMAC-SHA256 от <timestamp>.<raw body> с секретом подписи вашего рабочего пространства) позволяют проверить, что он пришёл от WbizTool. Как получить секрет и проверить подпись на Python и Node.js, описано в разделе Подписи вебхуков; получатели, которые не смотрят на эти заголовки, продолжают работать.
Ответьте любым кодом 2xx; если вы отвечаете перенаправлением, WbizTool переходит по нему не более 3 раз. Если ваш endpoint не отвечает в течение 10 секунд, недоступен или возвращает 429 либо 5xx, WbizTool повторяет вызов через 30 секунд, 1 минуту и 2 минуты (всего 4 попытки). Остальные ответы 4xx не повторяются. URL должен быть публичным интернет-адресом: webhook на частный или локальный адрес (например, 192.168.x.x или localhost) не отправляется.
Советы#
- Номера телефонов: храните номера в международном формате и передавайте их вместе с
country_code, чтобы избежать неоднозначности. - Переводы строк в JSON: записывайте их как
\nвнутриmsg. Непосредственный перенос строки делает JSON некорректным. - Держите номер подключённым: сообщения отправляются с вашего номера WhatsApp, поэтому он должен оставаться подключённым в настройках WhatsApp.
- Много получателей: чтобы отправить одно и то же сообщение на несколько номеров одним запросом, используйте Отправку на несколько номеров. Для крупных кампаний загрузите таблицу на странице Кампании.
