API для масових SMS v1
Невеликий REST API для надсилання масових SMS з вашого програмного забезпечення: JSON на вхід і вихід, Bearer ключі, ті самі ціни та перевірки, що й у консолі, та підписані вебхуки для звітів про доставку. Базовий URL https://smsbulk.cc/rest/v1
Огляд
Надсилайте до 8,000 номерів за один запит, кожен зі своїми значеннями для злиття, і API розраховує вартість для кожного одержувача з їх власним об’єднаним текстом, точно як у консолі. Спочатку запитайте котировку з тим самим текстом, щоб дізнатися вартість; нічого не надсилається та не стягується за котировку. Час вказується у форматі ISO 8601 в UTC, гроші, це рядок у доларах США з п’ятьма знаками після коми.
curl https://smsbulk.cc/rest/v1/send \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipients": [
{ "to": "+14155550142", "fields": { "name": "Maria" } },
{ "to": "+447400123456", "fields": { "name": "Tom" } }
],
"text": "Hi {{name}}, your order ships today.",
"client_ref": "order-batch-17"
}'const res = await fetch("https://smsbulk.cc/rest/v1/send", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
recipients: [
{ to: "+14155550142", fields: { name: "Maria" } },
{ to: "+447400123456", fields: { name: "Tom" } },
],
text: "Hi {{name}}, your order ships today.",
client_ref: "order-batch-17",
}),
});
const data = await res.json();
console.log(res.status, data.campaign?.id, data.campaign?.cost);import requests
res = requests.post(
"https://smsbulk.cc/rest/v1/send",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={
"recipients": [
{"to": "+14155550142", "fields": {"name": "Maria"}},
{"to": "+447400123456", "fields": {"name": "Tom"}},
],
"text": "Hi {{name}}, your order ships today.",
"client_ref": "order-batch-17",
},
timeout=30,
)
data = res.json()
print(res.status_code, data.get("campaign", {}).get("id"))<?php
$body = json_encode([
"recipients" => [
["to" => "+14155550142", "fields" => ["name" => "Maria"]],
["to" => "+447400123456", "fields" => ["name" => "Tom"]],
],
"text" => "Hi {{name}}, your order ships today.",
"client_ref" => "order-batch-17",
]);
$ch = curl_init("https://smsbulk.cc/rest/v1/send");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ["Authorization: Bearer YOUR_API_KEY", "Content-Type: application/json"],
CURLOPT_POSTFIELDS => $body,
]);
$data = json_decode(curl_exec($ch), true);
echo curl_getinfo($ch, CURLINFO_HTTP_CODE), " ", $data["campaign"]["id"] ?? "", PHP_EOL;Аутентифікація
Створіть ключ у консолі в розділі API та вебхуки; ключі стають доступними після першого поповнення вашого кредиту. Надсилайте його з кожним запитом як Bearer токен. Ключ показується один раз; ви можете мати до 5 ключів і відкликати будь-який з них одразу.
Authorization: Bearer smsb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxТарифи
Публічний, ключ не потрібен. Ціна за сегмент SMS для кожного напрямку або для одного коду ISO.
GEThttps://smsbulk.cc/rest/v1/rates
GEThttps://smsbulk.cc/rest/v1/rates/{ISO}
{
"country": "US",
"name": "United States",
"dial_code": "+1",
"rate": "0.00485",
"currency": "USD",
"per": "message segment"
}Кредит
GEThttps://smsbulk.cc/rest/v1/credit
{ "credit": "125.40000", "currency": "USD", "account": "A418820037715" }Котировка
Розраховує вартість надсилання без фактичного надсилання. Приймає той самий текст, що й Send.
POSThttps://smsbulk.cc/rest/v1/quote
| Поле | Тип | Значення |
|---|---|---|
| to | string or string[] | Один номер або список. Міжнародний формат з + є найбезпечнішим; локальні номери потребують default_country. |
| recipients | object[] | Замість to: список { to, fields }, де fields заповнюють поля злиття, такі як {{name}}. |
| text | string | Повідомлення, до 2,000 символів і 10 сегментів після злиття. |
| default_country | string | ISO код, що використовується для номерів, записаних без +, наприклад GB. Повертається до значення за замовчуванням, збереженого в Налаштуваннях. |
| opt_out | boolean | Додає ваш збережений текст відмови як останній рядок (спочатку збережіть його в Налаштуваннях). |
{
"recipients": 2,
"messages": 2,
"segments": { "min": 1, "max": 1 },
"encoding": "GSM-7",
"total": "0.01240",
"currency": "USD",
"credit": "125.40000",
"credit_after": "125.38760",
"countries": [
{ "country": "US", "recipients": 1, "rate": "0.00485", "segments": 1, "subtotal": "0.00485" },
{ "country": "GB", "recipients": 1, "rate": "0.00755", "segments": 1, "subtotal": "0.00755" }
],
"left_out": []
}Надіслати
Створює кампанію, списує її вартість з вашого кредиту та ставить повідомлення в чергу. Повертає 201 з кампанією. Номери, які не можна надіслати, перелічені в left_out і ніколи не стягуються.
POSThttps://smsbulk.cc/rest/v1/send
| Поле | Тип | Значення |
|---|---|---|
| to / recipients / text / default_country / opt_out | Як у Quote. | |
| send_at | string | Час старту у форматі ISO 8601, від 5 хвилин до 90 днів вперед. Залиште порожнім, щоб надіслати зараз. |
| name | string | Ваша мітка для кампанії, до 80 символів. |
| client_ref | string | Ваш власний посилання, до 64 символів, повертається на кожному повідомленні та вебхуку. |
HTTP/1.1 201 Created
{
"campaign": {
"id": "C507318264409",
"name": null,
"status": "sending",
"source": "api",
"test": false,
"recipients": 2,
"cost": "0.01240",
"refunded": "0.00000",
"net_cost": "0.01240",
"currency": "USD",
"send_at": null,
"created_at": "2026-11-07T14:02:11.000Z",
"started_at": "2026-11-07T14:02:11.000Z",
"finished_at": null,
"client_ref": "order-batch-17"
},
"messages": 2,
"left_out": []
}Кампанії
GEThttps://smsbulk.cc/rest/v1/campaigns?limit=25&before={id}
GEThttps://smsbulk.cc/rest/v1/campaigns/{id}
GEThttps://smsbulk.cc/rest/v1/campaigns/{id}/messages?status=failed&limit=100&after={message id}
Одна кампанія включає кількість за статусами: в черзі, надіслано, доставлено, невдало та скасовано. Списки повідомлень сторінкуються з after та has_more; до 1,000 на сторінці.
Повідомлення
GEThttps://smsbulk.cc/rest/v1/messages/{id}
GEThttps://smsbulk.cc/rest/v1/messages?to=%2B14155550142&status=delivered&client_ref=order-batch-17&limit=50
{
"id": "M220947781305",
"campaign": "C507318264409",
"to": "+14155550142",
"country": "US",
"segments": 1,
"encoding": "GSM-7",
"price": "0.00485",
"status": "delivered",
"reason": null,
"reason_text": null,
"refunded": false,
"client_ref": "order-batch-17",
"created_at": "2026-11-07T14:02:11.000Z",
"sent_at": "2026-11-07T14:02:12.000Z",
"finished_at": "2026-11-07T14:02:16.000Z"
}Скасувати заплановану кампанію
POSThttps://smsbulk.cc/rest/v1/campaigns/{id}/cancel
Працює до початкового часу. Повна вартість повертається на ваш кредит одним рядком у журналі, а статус кампанії стає скасованим.
Вебхуки
Встановіть URL кінцевої точки в консолі. Ми надсилаємо JSON для message.delivered, message.failed та campaign.done, а також тест, коли ви натискаєте Надіслати тестову подію. Кожна подія містить чотири заголовки, і будь-яка відповідь 2xx протягом 10 секунд вважається отриманою.
| Поле | Тип | Значення |
|---|---|---|
| Smsbulk-Event | заголовок | Назва події, наприклад message.delivered. |
| Smsbulk-Delivery | заголовок | Ідентифікатор доставки, однаковий при кожній повторній спробі однієї події. |
| Smsbulk-Timestamp | заголовок | Секунди Unix, коли ця спроба була підписана. |
| Smsbulk-Signature | заголовок | sha256=, за яким слідує base64 HMAC-SHA256 від мітки часу, нового рядка та необробленого тіла, зашифрованого вашим секретним sbw_. |
Доставка намагається 8 разів: одразу, потім через 1 хвилину, 5 хвилин, 15 хвилин, 1 годину, 3 години, 6 годин і 12 годин. Кожна спроба відображається в журналі доставки консолі з її HTTP статусом та початком вашої відповіді.
{
"id": "dlv_3f9a1c07b2e44d58a6c1",
"event": "message.failed",
"created": "2026-11-07T14:02:16.000Z",
"data": {
"message": "M220947781305",
"campaign": "C507318264409",
"to": "+447400123456",
"country": "GB",
"status": "failed",
"reason": "not_in_service",
"segments": 1,
"price": "0.00755",
"client_ref": "order-batch-17"
}
}Перевірте підпис
import crypto from "node:crypto";
// raw = the request body exactly as received (string), secret = your sbw_ signing secret
export function verify(raw, headers, secret) {
const ts = headers["smsbulk-timestamp"];
const want = "sha256=" + crypto.createHmac("sha256", secret).update(ts + "\n" + raw).digest("base64");
const got = headers["smsbulk-signature"] || "";
const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
return fresh && got.length === want.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(want));
}import base64, hashlib, hmac, time
def verify(raw: bytes, headers, secret: str) -> bool:
ts = headers.get("Smsbulk-Timestamp", "")
mac = hmac.new(secret.encode(), ts.encode() + b"\n" + raw, hashlib.sha256).digest()
want = "sha256=" + base64.b64encode(mac).decode()
fresh = abs(time.time() - int(ts or 0)) < 300
return fresh and hmac.compare_digest(want, headers.get("Smsbulk-Signature", ""))Помилки та обмеження
Помилки використовують HTTP статус і JSON тіло: {"error":{"code":"insufficient_credit","message":"..."}}. Нічого не стягується, якщо запит не вдається.
| Поле | Тип | Значення |
|---|---|---|
| 400 bad_json | Тіло не є JSON. | |
| 401 unauthorized | Відсутній, неправильно сформований або відкликаний ключ. | |
| 402 insufficient_credit | Загальна сума перевищує ваш баланс. Поповніть кошти в консолі. | |
| 404 not_found | Немає такого ендпоінту, кампанії, повідомлення або ISO коду в цьому акаунті. | |
| 409 not_scheduled | Скасування було запрошено для кампанії, яка вже розпочалася. | |
| 422 text_missing, text_too_long, too_many_segments | Повідомлення порожнє, перевищує 2,000 символів або має більше 10 сегментів для одного одержувача. | |
| 422 no_recipients, too_many, recipients_missing | Немає номера для відправки, більше 8,000 номерів або відсутні одержувачі. | |
| 422 schedule_range, bad_send_at | send_at поза межами від 5 хвилин до 90 днів або не є дійсним часом. | |
| 422 opt_out_unset | opt_out встановлено як true, але текст для відмови не збережено в Налаштуваннях. | |
| 429 rate_limited | Більше 300 запитів за хвилину для цього ключа. |
Кожна відповідь містить X-RateLimit-Limit, X-RateLimit-Remaining та X-RateLimit-Reset.
Виключені коди
Номери, видалені перед розрахунком ціни, повертаються в left_out з їх позицією у вашому списку, значенням, яке ви надіслали, кодом та простою причиною.
| Поле | Тип | Значення |
|---|---|---|
| no_country_code | Немає + та країни за замовчуванням. | |
| too_short / too_long | Менше 8 або більше 15 цифр. | |
| not_a_number | Літери або символи, які не є частиною номера. | |
| nanp_length | Номер +1 без одинадцяти цифр. | |
| not_covered | Пункт призначення поза нашим списком. | |
| duplicate | Цей номер вже з’являвся раніше в запиті. | |
| suppressed | Номер знаходиться у вашому списку виключень. |
Статуси та причини
| Поле | Тип | Значення |
|---|---|---|
| queued | статус | Очікування на вихід з нашої черги. |
| sent | статус | Передано мережі, очікування на звіт про доставку. Більшість звітів надходять протягом хвилин; деякі мережі можуть займати до 24 годин. |
| delivered | статус | Мережа підтвердила, що телефон отримав повідомлення. |
| failed | статус | Не доставлено. Сума була повернена на ваш баланс. |
| canceled | статус | Не відправлено через ваше скасування. Повернено. |
| Поле | Тип | Значення |
|---|---|---|
| network_error | причина | Помилка мережі |
| switched_off | причина | Телефон вимкнено або поза зоною покриття |
| not_in_service | причина | Номер не обслуговується |
| blocked | причина | Заблоковано мережею або одержувачем |
| landline | причина | Стаціонарний номер або номер, який не може отримувати SMS |
| content_filter | причина | Відхилено фільтром контенту мережі |
| expired | причина | Закінчився термін дії: немає звіту до закінчення часу мережі |
| unknown | причина | Невідома відповідь мережі |
| canceled | причина | Скасовано перед відправкою |
Питання щодо API? Відкрийте квиток у консолі або прочитайте FAQ.