Quick Start
Send your first SMS in under 5 minutes. All you need is your API key.
# Send an SMS via the SBS TELECOM REST API
curl -X POST https://portal.sbstelecom.net/api/v1/sms \
-u "YOUR_API_KEY:YOUR_API_SECRET" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-4471-sms" \
-d '{
"to": "+447911123456",
"from": "SBSTEL",
"text": "Hello from SBS TELECOM!"
}'
# Response — 202 Accepted
{
"message_id": "5f3c1b9a2e444c8a9f107b2d6c1e4a33",
"status": "queued",
"to": "+447911123456",
"from": "SBSTEL",
"charged": true,
"cost": 0.0175,
"balance": 499.7025
}
<?php
$ch = curl_init('https://portal.sbstelecom.net/api/v1/sms');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_USERPWD => 'YOUR_API_KEY:YOUR_API_SECRET',
CURLOPT_HTTPHEADER => [
'Content-Type: application/json',
'Idempotency-Key: order-4471-sms',
],
CURLOPT_POSTFIELDS => json_encode([
'to' => '+447911123456',
'from' => 'SBSTEL',
'text' => 'Hello from SBS TELECOM!',
]),
]);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
echo $res['message_id'];
import requests
response = requests.post(
'https://portal.sbstelecom.net/api/v1/sms',
auth=('YOUR_API_KEY', 'YOUR_API_SECRET'),
headers={'Idempotency-Key': 'order-4471-sms'},
json={
'to': '+447911123456',
'from': 'SBSTEL',
'text': 'Hello from SBS TELECOM!',
},
)
response.raise_for_status()
print(response.json()['message_id'])
const auth = Buffer.from('YOUR_API_KEY:YOUR_API_SECRET').toString('base64');
const response = await fetch('https://portal.sbstelecom.net/api/v1/sms', {
method: 'POST',
headers: {
'Authorization': `Basic ${auth}`,
'Content-Type': 'application/json',
'Idempotency-Key': 'order-4471-sms',
},
body: JSON.stringify({
to: '+447911123456',
from: 'SBSTEL',
text: 'Hello from SBS TELECOM!',
}),
});
const { message_id, status } = await response.json();
console.log(`Sent: ${message_id} — ${status}`);
Developer Sandbox
A dedicated sandbox for testing integrations without touching live traffic is on our roadmap. It is not available yet — no sandbox API endpoint, SMPP sandbox host or DLR simulation is currently offered.
Testing today
Integrate against your live account and send to a handset you control. Every message is charged at your normal rate, so testing costs are small and predictable.
Testing safely
Use an Idempotency-Key on every request while you develop. A repeated key never sends or charges twice, so re-running a test script cannot produce duplicate traffic.
Checking delivery
Poll GET /api/v1/sms/{id} for the real delivery outcome, or configure a DLR webhook in your portal to receive receipts as they arrive.
Need a sandbox?
If isolated test credentials would unblock your integration, let us know and we will factor it into the roadmap.
Contact SalesAuthentication
All API requests are authenticated with an API key and secret pair, issued in your client portal. Supply them as HTTP Basic credentials, as X-API-Key and X-API-Secret headers, or as a colon-separated bearer token.
| Header | Value | Required |
|---|---|---|
Authorization | Basic <base64 of KEY:SECRET> or Bearer <KEY>:<SECRET> | Required |
Content-Type | application/json | Required |
Idempotency-Key | Any unique string. Re-sending the same key never delivers or charges twice | Optional |
X-API-Key / X-API-Secret | Alternative to Basic auth — supply the pair as two headers | Optional |
Send SMS
POST /api/v1/sms
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
to | string | Required | E.164 format recipient number (+447911123456) |
from | string | Required | Alphanumeric sender ID (max 11 chars) or number |
text | string | Required | Message content. Multi-part handled automatically |
Bulk Messaging
A dedicated bulk/batch submission endpoint is on our roadmap. It is not available yet — there is currently no batch endpoint, and no batch identifiers or status URLs are issued.
Sending at volume today
Submit each message with POST /api/v1/sms and send concurrently. Your account’s throughput allowance governs the rate; the API returns 429 with a Retry-After header when you exceed it.
Making retries safe
Send an Idempotency-Key with every request. Re-sending the same key never delivers or charges twice, which makes a failed batch safe to replay in full.
Very high volumes
For sustained high-throughput traffic, our SMPP v3.4 binds are the supported route today and are documented below.
Need batch submission?
Tell us about your use case — customer demand shapes what we build next.
Contact SalesDLR Webhooks
SBS TELECOM posts real-time delivery receipts to the webhook URL configured in your client portal, via HTTP POST. Respond with 200 OK to acknowledge.
# Incoming DLR webhook POST payload
{
"message_id": "5f3c1b9a2e444c8a9f107b2d6c1e4a33",
"batch_id": "batch_01HX9A2B3C4D5E6F7G8H",
"to": "+447911123456",
"from": "SBSTEL",
"status": "DELIVRD",
"err_code": 0,
"err_desc": "Message delivered",
"submitted_at": "2026-03-26T10:00:00Z",
"delivered_at": "2026-03-26T10:00:01Z",
"network": "EE UK",
"mcc": "234",
"mnc": "30"
}
| Status | Description |
|---|---|
DELIVRD | Message delivered to handset |
ACCEPTD | Accepted by carrier, delivery pending |
UNDELIV | Undeliverable — invalid number or network error |
REJECTD | Rejected by carrier — content or sender ID issue |
EXPIRED | Validity period elapsed before delivery |
UNKNOWN | No DLR received from downstream carrier |
X-SBS-Signature header (HMAC-SHA256) against your webhook secret to verify authenticity of all incoming DLR callbacks.Error Codes
| HTTP | Code | Description |
|---|---|---|
| 400 | INVALID_NUMBER | Recipient number is not valid E.164 format |
| 400 | INVALID_SENDER | Sender ID exceeds 11 chars or uses disallowed chars |
| 400 | TEXT_TOO_LONG | Message exceeds 1600 characters (10 SMS parts) |
| 401 | INVALID_API_KEY | API key missing, expired or revoked |
| 402 | INSUFFICIENT_CREDIT | Account balance below minimum threshold |
| 403 | COUNTRY_BLOCKED | Destination country not enabled on your account |
| 429 | RATE_LIMITED | Too many requests — back-off and retry with exponential delay |
| 503 | GATEWAY_UNAVAILABLE | Temporary upstream issue — retry after Retry-After seconds |
SMPP v3.4 Overview
SBS TELECOM operates a purpose-built SMPP infrastructure supporting both SMPP v3.3 and v3.4. Designed for high-throughput platforms — fintechs, enterprise aggregators and OTP-heavy applications.
High-Throughput Binds
Up to 10,000 TPS per transceiver bind. Multiple concurrent binds supported for horizontal scaling.
TLS Encryption
All SMPP connections support TLS 1.2/1.3 on port 2776. Plain-text on port 2775 for legacy clients.
TLV Support
Full optional parameter (TLV) support including receipted_message_id, message_state, network_error_code and custom tags.
Unicode & Long SMS
GSM7, UCS-2 (Unicode) and 8-bit binary. Automatic segmentation and reassembly using SAR TLVs or UDH.
Connection Parameters
| Parameter | Value | Notes |
|---|---|---|
| Host | smpp.sbstelecom.co.uk | Production endpoint |
| Port (plain) | 2775 | Standard SMPP — legacy clients only |
| Port (TLS) | 2776 | Recommended — TLS 1.2 / 1.3 |
| Protocol | SMPP v3.3 / v3.4 | v3.4 recommended |
| system_id | Provided on account creation | Used for bind authentication |
| password | Max 8 characters | Rotatable in client portal |
| system_type | SMS or leave blank | Account-specific value if required |
| enquire_link | Every 30 seconds | Required — idle connections terminated after 60s |
| Encoding | data_coding=0 (GSM7), 8 (UCS-2) | See encoding table |
Bind Types
bind_transmitter
MO only — outbound SMS submission. Use when you only need to send messages and handle DLRs via HTTP webhook rather than SMPP deliver_sm.
command_id: 0x00000002
bind_receiver
Inbound only — receive DLR callbacks and inbound SMS (MO) over the SMPP connection as deliver_sm PDUs.
command_id: 0x00000001
bind_transceiver Recommended
Bidirectional — send and receive on a single connection. Recommended for high-throughput deployments and OTP platforms requiring low-latency DLRs.
command_id: 0x00000009
TLV (Optional) Parameters
SBS TELECOM supports the full SMPP v3.4 optional parameter set. Key TLVs for enterprise integrations:
| Tag | Hex | Direction | Description |
|---|---|---|---|
receipted_message_id | 0x001E | DLR | Original message ID in delivery receipts. Use to correlate DLRs with submissions |
message_state | 0x0427 | DLR | Final delivery state: 1=ENROUTE, 2=DELIVERED, 3=EXPIRED, 5=UNDELIVERABLE, 6=ACCEPTED |
network_error_code | 0x0423 | DLR | 3-byte field: network type byte + 2-byte error code from carrier |
sar_msg_ref_num | 0x020C | Submit | Reference number for long message segmentation (SAR). Use with sar_total_segments / sar_segment_seqnum |
sar_total_segments | 0x020E | Submit | Total number of segments in a concatenated message |
sar_segment_seqnum | 0x020F | Submit | Sequence number of this segment (1-based) |
dest_addr_subunit | 0x0005 | Submit | Flash SMS: set to 0x01 for Class 0 (display-only) messages |
user_message_reference | 0x0204 | Submit | Your internal reference ID. Echoed back in DLR deliver_sm |
callback_num | 0x0381 | Submit | Reply-to number for MO responses |
TLV Example — DLR Parsing
# Python: Parse TLV fields from deliver_sm DLR
def parse_dlr_tlvs(pdu):
msg_id = pdu.get_tlv(0x001E) # receipted_message_id
state = pdu.get_tlv(0x0427) # message_state (1=delivered, 5=undeliverable)
err_code = pdu.get_tlv(0x0423) # network_error_code
if state == 2:
mark_delivered(msg_id)
elif state == 5:
net_type = err_code[0]
net_err = int.from_bytes(err_code[1:3], 'big')
mark_failed(msg_id, net_type, net_err)
DLR & Callbacks over SMPP
Request DLRs on submit_sm by setting registered_delivery. Receipts arrive as deliver_sm PDUs on your receiver or transceiver bind.
| registered_delivery | Behaviour |
|---|---|
0x00 | No DLR requested |
0x01 | DLR on final delivery or failure only |
0x02 | DLR on delivery failure only |
0x03 | DLR on delivery success only |
0x10 | Intermediate DLRs (enroute state updates) |
0x11 | All DLRs — success, failure and intermediate (recommended for OTP) |
# submit_sm field summary for OTP with full DLR
submit_sm:
source_addr: "SBSBANK"
dest_addr: "+447911123456"
short_message: "Your OTP is 482910. Valid for 5 minutes."
data_coding: 0 # GSM7
registered_delivery: 0x11 # All DLRs
validity_period: "000000000005000R" # 5 minute expiry
TLVs:
user_message_reference: "TXN-98765-OTP" # your internal ref
Throughput & Window Sizing
Window Size
Default window size is 10 outstanding PDUs. Enterprise accounts can request up to 100 PDUs per bind for maximum throughput.
Multiple Binds
Scale horizontally by opening multiple transceiver binds. Each bind runs independently — ideal for load-balanced microservices.
Throughput Limits
Standard accounts: 100 TPS. Enterprise: 10,000 TPS per bind. Contact sales for high-volume OTP or financial alerting requirements.
enquire_link PDU every 30 seconds on idle connections. Connections without activity for 60 seconds will be closed by the server. Implement automatic reconnect with exponential back-off.PHP — Send with DLR Webhook
<?php
/**
* SBS TELECOM — Send SMS with DLR webhook (PHP)
* $apiCreds is your API key and secret as "KEY:SECRET".
*/
function sbstelSendSMS(string $apiCreds, array $params): array {
$ch = curl_init('https://portal.sbstelecom.net/api/v1/sms');
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => json_encode($params),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer {$apiCreds}",
'Content-Type: application/json',
],
CURLOPT_TIMEOUT => 10,
]);
$body = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($httpCode !== 200) {
throw new \RuntimeException("SMS API error {$httpCode}: {$body}");
}
return json_decode($body, true);
}
// Usage
$result = sbstelSendSMS('YOUR_API_KEY:YOUR_API_SECRET', [
'to' => '+447911123456',
'from' => 'SBSTEL',
'text' => 'Your verification code is 482910',
]);
echo "Sent: {$result['message_id']}";
// DLR webhook handler
$dlr = json_decode(file_get_contents('php://input'), true);
$sig = $_SERVER['HTTP_X_SBS_SIGNATURE'] ?? '';
$expected = hash_hmac('sha256', file_get_contents('php://input'), 'YOUR_WEBHOOK_SECRET');
if (!hash_equals($expected, $sig)) {
http_response_code(403); exit;
}
if ($dlr['status'] === 'DELIVRD') {
markDelivered($dlr['message_id']);
}
http_response_code(200);
Ready to Build?
Get your API credentials, explore the sandbox and integrate in minutes. Our engineering team is available for technical onboarding calls.