Перейти к содержимому
OmniChannels.ai
Меню

Отправка SMS через API: примеры на Python, Node.js, PHP и cURL

Отправка SMS через API на Python, Node.js, PHP и cURL: одиночные и массовые отправки, Unicode и арабский, подсчёт сегментов, вебхуки статусов доставки и ошибки.

Обновлено 10 мин чтения

Автор: 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 возвращает идентификатор сообщения обычным текстом, а итоговый статус доставки позже приходит на ваш вебхук.

На этой странице
  1. Как отправить SMS через API?
  2. Как форматировать номера телефонов?
  3. Как отправить арабский, эмодзи и другой текст в Unicode?
  4. Как подсчитать сегменты до отправки?
  5. Как отправить на много номеров?
  6. Как получать статус доставки?
  7. Как обрабатывать ошибки и избегать дубликатов?
  8. Пример: коды входа для регионального приложения
  9. Какие типичные ошибки?
  10. Как помогает 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.

  1. Сервис аутентификации генерирует шестизначный код, сохраняет его хеш со сроком действия пять минут и записывает отправку в статусе pending.
  2. Он вызывает /sms/sendSms с messageType=UNICODE для арабскоязычных пользователей и TEXT для англоязычных.
  3. При ответе 200 он сохраняет идентификатор сообщения.
  4. Обработчик вебхука отмечает запись как DELIVERED, FAILED или REJECTED.
  5. Если после короткого ожидания статус не DELIVERED, приложение предлагает повторную отправку и, если настроено, другой канал. См. резервный канал.
  6. Ограничения на запросы кода по номеру и по 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 для вашего направления; регистрацию вместе с вами может оформить наша команда.

Источники

  1. 3GPP TS 23.040: Technical realization of the Short Message Service (SMS)
  2. ITU-T E.164: The international public telecommunication numbering plan
  3. RFC 9110: HTTP Semantics