API Documentation

Full HTTP REST API reference for integrating SBS TELECOM messaging.

HTTP REST API Reference

The SBS TELECOM HTTP API lets you send SMS, query delivery status, poll inbound messages and check your balance programmatically.

Base URL

https://portal.sbstelecom.net/api/v1

The API is served by the customer portal, on the same origin you sign in to. There is no separate api. hostname.

Authentication

Every request needs an API key and secret — a pair, not a single token. Create them in the portal under Developer → API keys. Three forms are accepted:

# 1. HTTP Basic (recommended)
curl -u KEY:SECRET https://portal.sbstelecom.net/api/v1/balance

# 2. Dedicated headers
X-API-Key: KEY
X-API-Secret: SECRET

# 3. Bearer, colon-separated
Authorization: Bearer KEY:SECRET

Missing or incorrect credentials return 401. If an IP allow-list is set on the API key or on the connection, the source IP must satisfy both, otherwise the request returns 403 source IP not allowed.

Send a Message — POST /api/v1/sms

Send a single SMS. to and text are required; from defaults to the sender ID configured on your connection.

POST /api/v1/sms
Content-Type: application/json
Idempotency-Key: order-4471-sms

{
  "to": "+447911123456",
  "from": "SBSTEL",
  "text": "Your verification code is 847291"
}

Response 202 Accepted:

{
  "message_id": "5f3c1b9a2e44...",
  "status": "queued",
  "to": "+447911123456",
  "from": "SBSTEL",
  "charged": true,
  "cost": 0.0175,
  "balance": 499.7025
}

Safe Retries — Idempotency-Key

Send the same Idempotency-Key again and nothing is sent and nothing is charged; you get the original message back with 200 OK:

{
  "message_id": "5f3c1b9a2e44...",
  "status": "duplicate",
  "duplicate": true,
  "charged": false,
  "cost": 0
}

Tell a real send from a replay by the status code (202 vs 200) or the duplicate flag — never by message_id, which is identical in both. The key may also be given in the body as idempotency_key; the header wins.

Message Status — GET /api/v1/sms/{id}

{
  "message_id": "5f3c1b9a2e44...",
  "source": "SBSTEL",
  "dest": "447911123456",
  "status": "delivered",
  "dlr": "DELIVRD",
  "direction": "MT",
  "country": "United Kingdom",
  "operator": "EE"
}

An id outside your account returns 404.

Message Status Codes

  • queued — Accepted and charged, waiting for an egress
  • submitted — Handed to the carrier, no receipt yet
  • enroute — The carrier has it and is attempting delivery
  • delivered — Confirmed delivered to the handset
  • expired — Validity period elapsed before delivery
  • undeliverable — The carrier rejected it or gave up. Not retried
  • rejected — Refused before it reached a carrier

Inbound Messages — GET /api/v1/inbound

Poll for received (MO) messages. limit defaults to 100, maximum 500; results ascend by id.

GET /api/v1/inbound?since=0&limit=100

{ "messages": [ ... ], "next_since": 88213, "count": 12 }

Pass the returned next_since as since on your next poll to page forward with no gaps or repeats.

Account Balance — GET /api/v1/balance

{
  "balance": 499.70,
  "currency": "USD",
  "credit_limit": 100.00,
  "credit_used": 0.00,
  "available": 599.70,
  "payment_terms": "prepaid",
  "postpaid": false
}

Poll available, not balance. On a postpaid account sending stops when available reaches zero — which is at minus your credit limit, not at a zero balance.

Errors

Every error returns {"error":"message"}.

  • 400 — Invalid JSON, or to/text missing
  • 401 — Missing or invalid API credentials
  • 402 — Insufficient balance
  • 403 — Sender ID not approved or blocked; recipient opted out (replied STOP); source IP not allowed; identity verification required; message held for review
  • 404 — Message not found
  • 422 — No price or route for the destination
  • 429 — Rate limit exceeded (see Retry-After), or refused by a traffic control on your account
  • 500 — Submit failed

Rate Limits

The default allowance is 10 requests per second, applied as a token bucket per connection — all API keys on one connection share it, exactly as an SMPP bind is throttled. Exceeding it returns 429 with Retry-After: 1. Higher limits are available; contact support.