---
title: "Отправка SMS через API: примеры на Python, Node.js, PHP и cURL"
description: "Отправка SMS через API на Python, Node.js, PHP и cURL: одиночные и массовые отправки, Unicode и арабский, подсчёт сегментов, вебхуки статусов доставки и ошибки."
canonical: "https://omnichannels.ai/ru/blog/send-sms-api-examples/"
language: "ru"
updated: "2026-10-16"
publisher: "BroadNet Technologies"
brand: "OmniChannels.ai"
category: "integration"
primaryQuery: "sms api python пример отправки"
keywords: ["отправка sms python", "пример sms api node.js", "sms api php", "sms api curl", "sms api unicode арабский", "вебхук отчёта о доставке sms", "пример api для массовой sms-рассылки"]
published: "2026-10-16"
author: "OmniChannels.ai Editorial Team"
reviewer: "BroadNet Messaging Solutions Team"
readingMinutes: 10
answer: "Чтобы отправить SMS через API OmniChannels.ai, выполните аутентифицированный POST-запрос на https://api.broadnet.me/sms/sendSms с JSON-телом, содержащим senderId, destinationNumber, message и messageType. Для текста GSM-7 используйте TEXT, для арабского или эмодзи — UNICODE. Ответ 200 возвращает идентификатор сообщения обычным текстом, а итоговый статус доставки позже приходит на ваш вебхук."
takeaways: ["POST /sms/sendSms требует четыре поля: senderId, destinationNumber, message и messageType; тело ответа — идентификатор сообщения обычным текстом, а не JSON.", "Задавайте messageType UNICODE для арабского, эмодзи и любых символов вне GSM-7; один такой символ переводит всё сообщение в Unicode и укорачивает каждый сегмент.", "POST /sms/identify подсчитывает символы и сегменты до отправки, чтобы вы могли предсказать, сколько сегментов займёт сообщение.", "Доставка асинхронна: 200 означает, что сообщение принято, а DELIVERED, FAILED или REJECTED приходит позже на ваш вебхук.", "У API нет ключа идемпотентности, поэтому записывайте каждую отправку до вызова и после тайм-аута проверяйте статус, а не отправляйте повторно."]
faq: 
  - q: "Как отправить SMS на Python?"
    a: "Используйте библиотеку requests, чтобы отправить JSON POST-запросом на https://api.broadnet.me/sms/sendSms с заголовком Authorization: Bearer и полями senderId, destinationNumber, message и messageType. Читайте токен из переменной окружения. Тело ответа 200 — идентификатор сообщения обычным текстом, поэтому используйте r.text, а не r.json()."
  - q: "Какой формат номера телефона ожидает SMS API?"
    a: "Код страны плюс национальный номер, только цифры, без знака плюс, префикса 00, пробелов и ведущего нуля. Например, 447700900123 допустим, а +44 7700 900123 и 07700900123 — нет. Храните номера в базе в формате E.164 и убирайте знак плюс при формировании запроса."
  - q: "Как отправить SMS на арабском через API?"
    a: "Задайте messageType UNICODE и передайте арабский текст в поле message в UTF-8. Сообщение в Unicode вмещает 70 символов в одном сегменте и 67 в каждом сегменте при разделении, тогда как в GSM-7 — 160 и 153. Проверяйте на реальных телефонах и сначала вызовите /sms/identify, чтобы узнать число сегментов."
  - q: "Как получать отчёты о доставке?"
    a: "Статусы отправляются на URL вебхука, настроенный в вашем аккаунте. Сообщения проходят через SUBMITTED и SENT к DELIVERED, FAILED или REJECTED. Ваш эндпоинт должен сохранять исходное событие, быстро отвечать 2xx и обрабатывать данные асинхронно. Если события пропущены, POST /sms/resendDlr может повторно отправить отчёты за диапазон дат."
  - q: "Как отправить SMS сразу на много номеров?"
    a: "Используйте POST /sms/sendbulk — multipart-запрос с файлом destinationNumberFile (CSV или TXT) и JSON-строкой bulkRequest с senderId, message и messageType. В ответе указано, сколько номеров допустимых, недопустимых и дубликатов, и возвращается bulkSessionId, который можно сохранить вместе с кампанией."
  - q: "Нужно ли регистрировать Sender ID?"
    a: "Во многих странах — да. Где-то требуется одобренное буквенно-цифровое имя отправителя, а где-то идентификаторы регулятора или шаблона, которые API принимает в необязательных полях, например peId и templateId. Требования зависят от страны, поэтому смотрите страницу о Sender ID для вашего направления; регистрацию вместе с вами может оформить наша команда."
sources: 
  - title: "3GPP TS 23.040: Technical realization of the Short Message Service (SMS)"
    url: "https://www.3gpp.org/dynareport?code=23040"
  - title: "ITU-T E.164: The international public telecommunication numbering plan"
    url: "https://www.itu.int/rec/T-REC-E.164"
  - title: "RFC 9110: HTTP Semantics"
    url: "https://www.rfc-editor.org/rfc/rfc9110"
---

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

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

Это руководство для разработчиков, которым нужно отправлять SMS из приложения и рабочий код на Python, Node.js, PHP или cURL. Оно охватывает одиночную отправку, Unicode и арабский, подсчёт сегментов, массовую загрузку, вебхуки статусов доставки и обработку ошибок и использует только эндпоинты и поля из нашего [справочника SMS API](/developers/sms/) и спецификации 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` |

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

```bash
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"
  }'
```

```js
// 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(); // идентификатор сообщения обычным текстом
```

```python
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
<?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;
```

Тело успешного ответа выглядит так:

```text
2603121407537573731
```

Сохраните этот идентификатор в своей записи, например в заказе или попытке входа. По нему позже сопоставляются статусы доставки.

## Как форматировать номера телефонов?

Используйте код страны плюс национальный номер, только цифры. Формат следует международному плану нумерации ITU-T E.164 без знака плюс.

| Ввод | Допустимо? | Почему |
|---|---|---|
| `447700900123` | Да | Код страны 44 плюс национальный номер |
| `+44 7700 900123` | Нет | Уберите знак плюс и пробелы |
| `07700900123` | Нет | Замените ведущий 0 кодом страны |

Храните номера в базе в формате E.164 (`+447700900123`) и убирайте `+` при формировании запроса. Быструю проверку поможет сделать наш бесплатный форматировщик номеров телефонов.

## Как отправить арабский, эмодзи и другой текст в Unicode?

Задайте `messageType` значение `UNICODE`. Любой символ вне алфавита GSM-7, например арабская буква, эмодзи, типографская кавычка или длинное тире, переводит всё сообщение в Unicode.

```python
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](/ru/blog/sms-character-limits-unicode-arabic/) и попробуйте счётчик символов SMS.

## Как подсчитать сегменты до отправки?

Вызовите `POST /sms/identify` с сообщением. Он возвращает определённую кодировку, число символов, число сегментов и предел на сегмент.

```bash
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" }'
```

```json
{
  "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-строкой настроек.

```bash
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}'
```

```python
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-запросам](/ru/blog/hlr-lookup-number-validation/).

## Как получать статус доставки?

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

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

```js
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` повторно отправляет отчёты за диапазон дат:

```bash
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"
  }'
```

Подробнее — в [руководстве по вебхукам](/developers/webhooks/) и в материале о статусах доставки сообщений.

## Как обрабатывать ошибки и избегать дубликатов?

Сначала обрабатывайте 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`. Подробности — в разделе [ошибки и лимиты](/developers/errors-and-limits/).

## Пример: коды входа для регионального приложения

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

1. Сервис аутентификации генерирует шестизначный код, сохраняет его хеш со сроком действия пять минут и записывает отправку в статусе `pending`.
2. Он вызывает `/sms/sendSms` с `messageType=UNICODE` для арабскоязычных пользователей и `TEXT` для англоязычных.
3. При ответе `200` он сохраняет идентификатор сообщения.
4. Обработчик вебхука отмечает запись как `DELIVERED`, `FAILED` или `REJECTED`.
5. Если после короткого ожидания статус не `DELIVERED`, приложение предлагает повторную отправку и, если настроено, другой канал. См. резервный канал.
6. Ограничения на запросы кода по номеру и по IP защищают от злоупотреблений; см. [защиту от SMS pumping](/ru/blog/sms-pumping-fraud-prevention/).

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

- **Вызов `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](/developers/sms/) или канал SMS.
