Skip to content
OmniChannels.ai

SMS API

Send single and bulk SMS, choose TEXT or UNICODE encoding, count segments, schedule, control bulk jobs and look up numbers before you send.

Base URL https://api.broadnet.meUpdated

The SMS API sends one message with a JSON request, or many messages from an uploaded file, over direct operator connectivity. This page covers single sends, encoding and segments, bulk jobs and number lookup.

Endpoints at a glance#

Method Path Use it to
POST /sms/sendSms Send one SMS (JSON). Returns the message ID.
POST /sms/identify Detect encoding and count characters and segments.
POST /sms/sendbulk Send one message to a file of numbers (multipart).
GET /sms/list List bulk jobs with processed and pending counts.
GET /sms/edit Read the details of one bulk job.
GET /sms/pause Pause a running bulk job.
GET /sms/resume Resume a paused bulk job.
DELETE /sms/abort Abort a bulk job; pending messages are not sent.
GET /sms/listSchedule List scheduled campaigns.
POST /sms/send-now Release a scheduled campaign immediately.
DELETE /sms/abort/schedule Cancel a scheduled campaign.
POST /sms/lookup Check a number's status (HLR / MNP) before sending.

Send a single SMS#

POST /sms/sendSms takes a JSON body and returns 200 OK with the message ID as plain text.

Request fields#

Field Type Required Description
senderId string Yes Your approved sender ID, shown to the recipient.
destinationNumber string Yes Country code plus number, digits only. No +, 00, spaces or leading zero.
message string Yes The message text.
messageType string Yes TEXT for GSM-7 text, UNICODE for Arabic, emoji and other scripts.
charCount integer No Character count, as returned by /sms/identify.
smsParts integer No Number of segments, as returned by /sms/identify.
charLimit integer No Characters per segment, as returned by /sms/identify.
expiryHour integer No Validity period in hours.
campaignName string No Your label, used in reporting.
isSchedule boolean No true to schedule instead of sending now.
time — No Scheduled send time (used with isSchedule).
gmt string No GMT offset for the scheduled time, for example +04:00.
repeat — No Repeat setting for scheduled sends.
delay number No Delay before sending.
peId string No Principal entity ID, where a regulator requires one.
templateId string No Registered content template ID, where a regulator requires one.
telemarketerId string No Telemarketer ID, where a regulator requires one.

Use exactly these field names. Fields such as to, from or text are not part of this endpoint. Leave the scheduling fields out to send immediately; for scheduled campaigns, the bulk endpoints below are the better fit, and our team can confirm the expected time format for your account.

Example#

cURL

curl -X POST https://api.broadnet.me/sms/sendSms \
  -H "Authorization: Bearer $BROADNET_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "senderId": "OmniDemo",
    "destinationNumber": "971500000000",
    "message": "رمز التحقق الخاص بك هو 482913",
    "messageType": "UNICODE",
    "campaignName": "login-otp"
  }'

Node.js

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: "971500000000",
    message: "رمز التحقق الخاص بك هو 482913",
    messageType: "UNICODE",
    campaignName: "login-otp",
  }),
});
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": "971500000000",
        "message": "رمز التحقق الخاص بك هو 482913",
        "messageType": "UNICODE",
        "campaignName": "login-otp",
    },
    timeout=15,
)
r.raise_for_status()
message_id = r.text

PHP

<?php
$ch = curl_init("https://api.broadnet.me/sms/sendSms");
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("BROADNET_TOKEN"),
        "Content-Type: application/json",
    ],
    CURLOPT_POSTFIELDS => json_encode([
        "senderId" => "OmniDemo",
        "destinationNumber" => "971500000000",
        "message" => "رمز التحقق الخاص بك هو 482913",
        "messageType" => "UNICODE",
        "campaignName" => "login-otp",
    ], JSON_UNESCAPED_UNICODE),
]);
$messageId = curl_exec($ch);
curl_close($ch);

The response body is the message ID:

Response

2603121407537573731

Phone number format#

Input Valid? Why
447700900123 Yes Country code 44 plus the national number, digits only.
+44 7700 900123 No Remove the + and spaces first.
07700900123 No National format: replace the leading 0 with the country code.

Store numbers in E.164 (+447700900123) in your own database and strip the + when you build the request.

Encoding and segments#

messageType sets the encoding, and the encoding sets how many characters fit in each SMS segment. Long messages are split into segments and reassembled on the handset; most operators bill per segment.

messageType Single SMS Per segment when split Use for
TEXT 160 characters 153 characters Text that uses only the GSM-7 alphabet.
UNICODE 70 characters 67 characters Arabic, Cyrillic, Chinese, emoji, and characters outside GSM-7.

A single non-GSM-7 character switches the whole message to Unicode. Common culprits are curly quotes, the em dash, the ellipsis character and emoji.

Let the API count for you#

POST /sms/identify analyses a message and returns its encoding, character count, segment count and per-segment limit. You can pass the values straight into a send request.

cURL

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

The response describes the message:

Response

{
  "message": "Your OmniDemo code is 482913",
  "messageType": "TEXT",
  "smscount": 1,
  "charCount": 28,
  "charLimit": 160
}
Response field Description
messageType Detected encoding. GSM-7 text may be labelled GSM-7; send it as TEXT.
smscount Number of segments needed. Map it to smsParts in a send request.
charCount Total characters.
charLimit Characters per segment: 160, 153, 70 or 67.

Send in bulk#

POST /sms/sendbulk sends one message to every number in an uploaded file. It is a multipart/form-data request with two parts:

Part Type Required Description
destinationNumberFile file Yes CSV or TXT file of numbers, one per line, in the same format as destinationNumber.
bulkRequest string (JSON) Yes The message settings, as a JSON string.

Fields inside bulkRequest:

Field Type Required Description
senderId string Yes Your approved sender ID.
message string Yes The message text.
messageType string Yes TEXT or UNICODE.
campaignName string No Your label for reporting.
allowDuplicate boolean No false removes duplicate numbers from the file.
expiryHour integer No Validity period in hours.
delay number No Throttle between messages.
schedule boolean No true to schedule the job.
smsParts, charCount, charLimit integer No Values from /sms/identify.
peId, templateId, telemarketerId string No Regulatory IDs, where required.

cURL

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())

A successful upload returns a job summary:

Response

{
  "status": "success",
  "bulkSessionId": "1_20260228105000887",
  "credits": "9966465.42850",
  "deductcredits": "0.60000",
  "bulkListInfo": {
    "total": 4,
    "validCount": 3,
    "invalidCount": 0,
    "duplicate": 1,
    "errors": {}
  }
}

bulkListInfo tells you how many numbers were accepted, rejected as invalid, or removed as duplicates. credits is your remaining balance and deductcredits the amount charged for the job. Store bulkSessionId with your campaign record.

Control bulk jobs#

Running jobs are identified by the id returned from GET /sms/list. Pass it as the batch_Id query parameter to the other job endpoints.

cURL

# 1. List jobs: each entry has an id, total, processed, pending and active
curl https://api.broadnet.me/sms/list \
  -H "Authorization: Bearer $BROADNET_TOKEN"

# 2. Pause, resume or abort a job by its id
curl "https://api.broadnet.me/sms/pause?batch_Id=1024" -H "Authorization: Bearer $BROADNET_TOKEN"
curl "https://api.broadnet.me/sms/resume?batch_Id=1024" -H "Authorization: Bearer $BROADNET_TOKEN"
curl -X DELETE "https://api.broadnet.me/sms/abort?batch_Id=1024" -H "Authorization: Bearer $BROADNET_TOKEN"

Each entry in the list looks like this (abridged):

GET /sms/list

[
  {
    "id": 1024,
    "senderId": "OmniDemo",
    "reqType": "bulk",
    "messageType": "GSM-7",
    "campaignName": "oct-statements",
    "total": 1000,
    "processed": 450,
    "pending": 550,
    "active": true,
    "createdOn": "2026-10-08T21:15:20"
  }
]
Action Call Notes
Inspect GET /sms/edit?batch_Id=… Full details of one job.
Pause GET /sms/pause?batch_Id=… Only active jobs can be paused.
Resume GET /sms/resume?batch_Id=… Continues from where it stopped.
Abort DELETE /sms/abort?batch_Id=… Permanent; pending messages are not sent.

GET /sms/list is not paginated; it returns all of your bulk jobs in one response.

Scheduled campaigns#

GET /sms/listSchedule returns your scheduled campaigns, each with an id. Use that ID with POST /sms/send-now to release a campaign immediately, or with DELETE /sms/abort/schedule?scheduleId=… to cancel it.

Look up a number before sending#

POST /sms/lookup checks a number against the network (HLR and MNP) so you can clean lists and route ported numbers correctly. Pass the number in the destinationNumber query parameter. The optional reqType parameter selects the kind of lookup; ask our team which values are enabled on your account.

cURL

curl -X POST "https://api.broadnet.me/sms/lookup?destinationNumber=447700900123" \
  -H "Authorization: Bearer $BROADNET_TOKEN"

Lookup traffic has its own default rate limit. See Errors and limits.

High volume over SMPP#

If you already run an SMPP client or need sustained high throughput, the same SMS routes are available over SMPP v3.4 with TLS. See SMPP.

Next steps#

  • Webhooks: receive DELIVERED, FAILED and other statuses.
  • Errors and limits: retries, rate limits and duplicate protection.
  • RCS: upgrade SMS to branded rich messages where handsets support it.
  • SMPP: bind for high-volume SMS.

Ready to send your first message?

Request test credentials. An engineer sets up your account, and test sends go to your own verified numbers.

Request test access