Отправка SMS через API: примеры на Python, Node.js, PHP и cURL
Отправка SMS через API на Python, Node.js, PHP и cURL: одиночные и массовые отправки, Unicode и арабский, подсчёт сегментов, вебхуки статусов доставки и ошибки.
Автор: OmniChannels.ai Editorial Team · Проверил: BroadNet Messaging Solutions Team
Интеграции
Короткий ответ
Чтобы отправить SMS через API OmniChannels.ai, выполните аутентифицированный POST-запрос на https://api.broadnet.me/sms/sendSms с JSON-телом, содержащим senderId, destinationNumber, message и messageType. Для текста GSM-7 используйте TEXT, для арабского или эмодзи — UNICODE. Ответ 200 возвращает идентификатор сообщения обычным текстом, а итоговый статус доставки позже приходит на ваш вебхук.
На этой странице
- Как отправить SMS через API?
- Как форматировать номера телефонов?
- Как отправить арабский, эмодзи и другой текст в Unicode?
- Как подсчитать сегменты до отправки?
- Как отправить на много номеров?
- Как получать статус доставки?
- Как обрабатывать ошибки и избегать дубликатов?
- Пример: коды входа для регионального приложения
- Какие типичные ошибки?
- Как помогает OmniChannels.ai
Главное
- POST /sms/sendSms требует четыре поля: senderId, destinationNumber, message и messageType; тело ответа — идентификатор сообщения обычным текстом, а не JSON.
- Задавайте messageType UNICODE для арабского, эмодзи и любых символов вне GSM-7; один такой символ переводит всё сообщение в Unicode и укорачивает каждый сегмент.
- POST /sms/identify подсчитывает символы и сегменты до отправки, чтобы вы могли предсказать, сколько сегментов займёт сообщение.
- Доставка асинхронна: 200 означает, что сообщение принято, а DELIVERED, FAILED или REJECTED приходит позже на ваш вебхук.
- У API нет ключа идемпотентности, поэтому записывайте каждую отправку до вызова и после тайм-аута проверяйте статус, а не отправляйте повторно.
Это руководство для разработчиков, которым нужно отправлять SMS из приложения и рабочий код на Python, Node.js, PHP или cURL. Оно охватывает одиночную отправку, Unicode и арабский, подсчёт сегментов, массовую загрузку, вебхуки статусов доставки и обработку ошибок и использует только эндпоинты и поля из нашего справочника SMS API и спецификации OpenAPI.
Как отправить SMS через API?
Выполните аутентифицированный POST на /sms/sendSms с JSON-телом. Ответ — 200 OK с идентификатором сообщения обычным текстом.
| Параметр | Значение |
|---|---|
| Базовый URL | https://api.broadnet.me (без префикса /v1) |
| Эндпоинт | POST /sms/sendSms |
| Аутентификация | Authorization: Bearer $BROADNET_TOKEN |
| Тип содержимого | application/json |
| Обязательные поля | senderId, destinationNumber, message, messageType |
Тестовые учётные данные выдаются после краткого запроса доступа, а тестовые отправки идут на ваши собственные подтверждённые номера. Мгновенной саморегистрации нет. См. быстрый старт.
curl -X POST https://api.broadnet.me/sms/sendSms \
-H "Authorization: Bearer $BROADNET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"senderId": "OmniDemo",
"destinationNumber": "447700900123",
"message": "Your OmniDemo code is 482913",
"messageType": "TEXT"
}'
// Node.js 18+ (встроенный fetch)
const res = await fetch("https://api.broadnet.me/sms/sendSms", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.BROADNET_TOKEN}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
senderId: "OmniDemo",
destinationNumber: "447700900123",
message: "Your OmniDemo code is 482913",
messageType: "TEXT",
}),
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const messageId = await res.text(); // идентификатор сообщения обычным текстом
import os
import requests
r = requests.post(
"https://api.broadnet.me/sms/sendSms",
headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
json={
"senderId": "OmniDemo",
"destinationNumber": "447700900123",
"message": "Your OmniDemo code is 482913",
"messageType": "TEXT",
},
timeout=15,
)
r.raise_for_status()
message_id = r.text # идентификатор сообщения обычным текстом, не JSON
<?php
$payload = json_encode([
"senderId" => "OmniDemo",
"destinationNumber" => "447700900123",
"message" => "Your OmniDemo code is 482913",
"messageType" => "TEXT",
]);
$ch = curl_init("https://api.broadnet.me/sms/sendSms");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 15,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("BROADNET_TOKEN"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => $payload,
]);
$messageId = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
echo $status . " " . $messageId . PHP_EOL;
Тело успешного ответа выглядит так:
2603121407537573731
Сохраните этот идентификатор в своей записи, например в заказе или попытке входа. По нему позже сопоставляются статусы доставки.
Как форматировать номера телефонов?
Используйте код страны плюс национальный номер, только цифры. Формат следует международному плану нумерации ITU-T E.164 без знака плюс.
| Ввод | Допустимо? | Почему |
|---|---|---|
447700900123 |
Да | Код страны 44 плюс национальный номер |
+44 7700 900123 |
Нет | Уберите знак плюс и пробелы |
07700900123 |
Нет | Замените ведущий 0 кодом страны |
Храните номера в базе в формате E.164 (+447700900123) и убирайте + при формировании запроса. Быструю проверку поможет сделать наш бесплатный форматировщик номеров телефонов.
Как отправить арабский, эмодзи и другой текст в Unicode?
Задайте messageType значение UNICODE. Любой символ вне алфавита GSM-7, например арабская буква, эмодзи, типографская кавычка или длинное тире, переводит всё сообщение в Unicode.
r = requests.post(
"https://api.broadnet.me/sms/sendSms",
headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
json={
"senderId": "OmniDemo",
"destinationNumber": "971500000000",
"message": "رمز التحقق الخاص بك هو 482913",
"messageType": "UNICODE",
"campaignName": "login-otp",
},
timeout=15,
)
В PHP при вызове json_encode используйте JSON_UNESCAPED_UNICODE. Кодировка определяет размер сегмента, как для SMS задано в 3GPP TS 23.040:
messageType |
Одно SMS | В сегменте при разделении | Для чего |
|---|---|---|---|
TEXT |
160 символов | 153 символа | Текст только из алфавита GSM-7 |
UNICODE |
70 символов | 67 символов | Арабский, кириллица, китайский, эмодзи |
Большинство операторов тарифицирует по сегментам, поэтому длинное сообщение на арабском стоит дороже такого же по длине на латинице. Прочитайте наше руководство по Unicode и арабским SMS и попробуйте счётчик символов SMS.
Как подсчитать сегменты до отправки?
Вызовите POST /sms/identify с сообщением. Он возвращает определённую кодировку, число символов, число сегментов и предел на сегмент.
curl -X POST https://api.broadnet.me/sms/identify \
-H "Authorization: Bearer $BROADNET_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "message": "Your OmniDemo code is 482913" }'
{
"message": "Your OmniDemo code is 482913",
"messageType": "TEXT",
"smscount": 1,
"charCount": 28,
"charLimit": 160
}
В запрос на отправку можно передать smsParts (из smscount), charCount и charLimit. Текст GSM-7 в ответе может быть помечен как GSM-7; отправляйте его как TEXT.
Как отправить на много номеров?
Используйте POST /sms/sendbulk — запрос multipart/form-data с файлом получателей и JSON-строкой настроек.
curl -X POST https://api.broadnet.me/sms/sendbulk \
-H "Authorization: Bearer $BROADNET_TOKEN" \
-F destinationNumberFile=@recipients.csv \
-F 'bulkRequest={"senderId":"OmniDemo","message":"Your statement is ready in the app.","messageType":"TEXT","campaignName":"oct-statements","allowDuplicate":false}'
import json
import os
import requests
bulk_request = {
"senderId": "OmniDemo",
"message": "Your statement is ready in the app.",
"messageType": "TEXT",
"campaignName": "oct-statements",
"allowDuplicate": False,
}
with open("recipients.csv", "rb") as f:
r = requests.post(
"https://api.broadnet.me/sms/sendbulk",
headers={"Authorization": f"Bearer {os.environ['BROADNET_TOKEN']}"},
files={"destinationNumberFile": ("recipients.csv", f, "text/csv")},
data={"bulkRequest": json.dumps(bulk_request)},
timeout=60,
)
print(r.json())
Ответ содержит bulkSessionId и объект bulkListInfo с total, validCount, invalidCount и duplicate. Сохраните bulkSessionId вместе с кампанией. Задачи можно просматривать, приостанавливать, возобновлять и прерывать с помощью эндпоинтов из справочника. Кроме того, перед большой рассылкой можно проверить номера через POST /sms/lookup; см. наше руководство по HLR-запросам.
Как получать статус доставки?
Статусы доставки отправляются на URL вебхука, настроенный в вашем аккаунте. Сообщение проходит через SUBMITTED и SENT к DELIVERED либо завершается как FAILED или REJECTED. Вы сообщаете нашей команде публичный HTTPS URL, а у реселлеров может быть по одному вебхуку на каждый субаккаунт.
Поля payload различаются по каналам, а в спецификации API нет единой схемы вебхука, поэтому сначала логируйте исходное тело и сопоставляйте поля по реальному событию в вашем аккаунте. Минимальный приёмник сохраняет событие и быстро подтверждает получение:
import express from "express";
const app = express();
app.post("/webhooks/omnichannels", express.json(), async (req, res) => {
await saveStatusEvent(req.body); // ваше хранилище; обрабатывайте асинхронно
res.sendStatus(200); // подтверждайте быстро
});
app.listen(3000);
Делайте обработку идемпотентной, потому что один и тот же статус может прийти дважды, и никогда не позволяйте запоздавшему SENT перезаписать сохранённый DELIVERED. Если ваш эндпоинт был недоступен, POST /sms/resendDlr повторно отправляет отчёты за диапазон дат:
curl -X POST https://api.broadnet.me/sms/resendDlr \
-H "Authorization: Bearer $BROADNET_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"startDate": "2026-10-09",
"endDate": "2026-10-10",
"senderId": "OmniDemo",
"messageStatus": "DELIVERED"
}'
Подробнее — в руководстве по вебхукам и в материале о статусах доставки сообщений.
Как обрабатывать ошибки и избегать дубликатов?
Сначала обрабатывайте HTTP-статус, затем тело ошибки. Повторяйте только при сетевых ошибках, 429 и 5xx.
| Код | Значение | Действие |
|---|---|---|
200 |
Принято | Сохраните идентификатор |
400 |
Ошибка валидации или отсутствует поле | Исправьте запрос |
401 / 403 |
Неверный токен или операция не разрешена | Исправьте; не повторяйте |
429 |
Превышен лимит запросов | Подождите значение Retry-After |
500, 503, 504 |
Проблема на сервере или у вышестоящего узла | Повторяйте с отсрочкой и jitter |
Ошибки API возвращаются JSON-телом из пяти полей: status, error, message, errorCode и requestUri. Документированный лимит REST по умолчанию — 200 запросов в секунду на постоянной основе; лимиты вашего аккаунта подтверждаются вместе с учётными данными.
API не принимает ключ идемпотентности. Запрос может выполниться, а ответ потеряться, и тогда слепой повтор отправит сообщение дважды. Перед вызовом запишите строку со статусом pending, ключом которой будет ваш собственный идентификатор операции, сохраните возвращённый идентификатор сообщения, а после тайм-аута проверьте статус по вебхуку, прежде чем отправлять снова. Для массовых отправок задавайте allowDuplicate значение false. Подробности — в разделе ошибки и лимиты.
Пример: коды входа для регионального приложения
«Souq Rafiq» (условный пример), розничный продавец из ОАЭ, отправляет коды входа по SMS.
- Сервис аутентификации генерирует шестизначный код, сохраняет его хеш со сроком действия пять минут и записывает отправку в статусе
pending. - Он вызывает
/sms/sendSmsсmessageType=UNICODEдля арабскоязычных пользователей иTEXTдля англоязычных. - При ответе
200он сохраняет идентификатор сообщения. - Обработчик вебхука отмечает запись как
DELIVERED,FAILEDилиREJECTED. - Если после короткого ожидания статус не
DELIVERED, приложение предлагает повторную отправку и, если настроено, другой канал. См. резервный канал. - Ограничения на запросы кода по номеру и по IP защищают от злоупотреблений; см. защиту от SMS pumping.
Какие типичные ошибки?
- Вызов
r.json()для ответа на отправку. Это обычный текст. - Неверные имена полей. Используйте
senderId,destinationNumberиmessage; поля вродеto,fromилиtextв этом эндпоинте не используются. - Знаки плюс и ведущие нули в номерах.
- Забытый
UNICODEдля арабского, из-за чего текст искажается. - Незарегистрированные Sender ID. В некоторых странах их блокируют или заменяют; проверьте правила для вашего направления и попросите нас оформить регистрацию.
- Принятие
200за доставку. - Токен в мобильном приложении или браузере, откуда его может извлечь кто угодно.
- Ограничения: в этом руководстве показан типичный запрос. Необязательные поля, например форматы планирования, уточняйте у нашей команды.
Как помогает OmniChannels.ai
OmniChannels.ai отправляет A2P SMS через прямые подключения BroadNet к операторам, с двусторонними SMS, именами отправителей, Unicode и арабским, HLR-запросами и SMPP 3.4 для больших объёмов. REST API на https://api.broadnet.me использует Bearer-токен и охватывает также WhatsApp, RCS и другие каналы, а статусы доставки приводятся к единому формату вебхука. Наша команда вместе с вами готовит регистрацию имён отправителей. См. справочник SMS API или канал SMS.
Часто задаваемые вопросы
Как отправить SMS на Python?
Используйте библиотеку requests, чтобы отправить JSON POST-запросом на https://api.broadnet.me/sms/sendSms с заголовком Authorization: Bearer и полями senderId, destinationNumber, message и messageType. Читайте токен из переменной окружения. Тело ответа 200 — идентификатор сообщения обычным текстом, поэтому используйте r.text, а не r.json().
Какой формат номера телефона ожидает SMS API?
Код страны плюс национальный номер, только цифры, без знака плюс, префикса 00, пробелов и ведущего нуля. Например, 447700900123 допустим, а +44 7700 900123 и 07700900123 — нет. Храните номера в базе в формате E.164 и убирайте знак плюс при формировании запроса.
Как отправить SMS на арабском через API?
Задайте messageType UNICODE и передайте арабский текст в поле message в UTF-8. Сообщение в Unicode вмещает 70 символов в одном сегменте и 67 в каждом сегменте при разделении, тогда как в GSM-7 — 160 и 153. Проверяйте на реальных телефонах и сначала вызовите /sms/identify, чтобы узнать число сегментов.
Как получать отчёты о доставке?
Статусы отправляются на URL вебхука, настроенный в вашем аккаунте. Сообщения проходят через SUBMITTED и SENT к DELIVERED, FAILED или REJECTED. Ваш эндпоинт должен сохранять исходное событие, быстро отвечать 2xx и обрабатывать данные асинхронно. Если события пропущены, POST /sms/resendDlr может повторно отправить отчёты за диапазон дат.
Как отправить SMS сразу на много номеров?
Используйте POST /sms/sendbulk — multipart-запрос с файлом destinationNumberFile (CSV или TXT) и JSON-строкой bulkRequest с senderId, message и messageType. В ответе указано, сколько номеров допустимых, недопустимых и дубликатов, и возвращается bulkSessionId, который можно сохранить вместе с кампанией.
Нужно ли регистрировать Sender ID?
Во многих странах — да. Где-то требуется одобренное буквенно-цифровое имя отправителя, а где-то идентификаторы регулятора или шаблона, которые API принимает в необязательных полях, например peId и templateId. Требования зависят от страны, поэтому смотрите страницу о Sender ID для вашего направления; регистрацию вместе с вами может оформить наша команда.
Источники
Читайте дальше
Ещё руководстваИнтеграции
Отправка сообщения WhatsApp через API: cURL, Node, Python, PHP
Как отправить сообщение WhatsApp через API: рабочие примеры на cURL, Node.js, Python и PHP для шаблонов и сессионных сообщений, отслеживание статусов и ошибки.
10 мин чтения
Интеграции
Как выбрать API для обмена сообщениями: чек-лист для CTO
Как выбрать API для сообщений: чек-лист для CTO по каналам, качеству маршрутов, вебхукам, безопасности, лимитам, повторам, SMPP, MCP, комплаенсу и ценам.
13 мин чтения
SMS и OTP
Как выбрать провайдера массовой SMS-рассылки: 12 пунктов
Как выбрать провайдера SMS-рассылки: 12 проверок маршрутов, отчётов о доставке, Sender ID, цен, поддержки и комплаенса, плюс тест-план до подписания договора.
10 мин чтения
