Skip to main content

Minimal send

curl -X POST https://api.robase.dev/v1/sms \
  -H "Authorization: Bearer rb_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"to":"+2348012345678","from":"SHUTTLERS","body":"Your ride arrives in 3 minutes."}'
{
  "id": "01H8XKQJ3Z9S7K1X2Y3Z4A5B",
  "status": "queued",
  "to": "+2348012345678",
  "from": "SHUTTLERS",
  "body": "Your ride arrives in 3 minutes.",
  "segments": 1,
  "encoding": "GSM7",
  "country": "NG",
  "cost": { "amount_kobo": 400, "currency": "NGN" },
  "provider": "beem",
  "test_mode": false,
  "created_at": "2026-04-17T10:30:00Z"
}

Request parameters

to
string
required
Recipient phone number in E.164 format (+ followed by 8–15 digits). We auto-detect the country from the dial code. Invalid numbers return phone_invalid.
from
string
required
Sender ID — alphanumeric, ≤ 11 characters. Must be registered in your project. See Sender IDs.
body
string
Message body. Required unless template is provided. Max 1600 characters (concatenated SMS auto-splits into segments).
template
string
Slug or UUID of a registered SMS template. When set, body is ignored and rendered from the template using variables. See Templates.
variables
object
Map of variable → value for template interpolation. Only used when template is set.
{ "driver_name": "Chidi", "eta": 3 }
country
string
ISO-3166 alpha-2 code (NG, GH, KE, CI). Optional — we derive it from to by default. Use this to override for hybrid-numbered SIMs.
send_at
string (ISO 8601)
Schedule delivery for a future time. The message stays in scheduled state until the scheduled time, then transitions to queued and sends. Max lead time: 30 days.

Response

id
string
Globally unique message ID. Use this to fetch the message later.
status
string
One of: queued, scheduled, sent, delivered, failed, rejected, cancelled. New messages start as queued (or scheduled if send_at is in the future).
segments
integer
Number of SMS segments the body occupies. GSM-7 body: 160/153 chars per segment. UCS-2 (emoji, non-Latin): 70/67.
encoding
string
GSM7 or UCS2. We detect automatically based on body content.
cost
object
Per-segment cost committed for this send. amount_kobo is the smallest unit of currency (e.g. kobo for NGN, pesewas for GHS).
provider
string
Upstream we initially routed to. The actual winning provider after failover is on GET /v1/sms/:id in provider_attempts.
test_mode
boolean
true when sent with a rb_test_* key. Test messages never touch real carriers.

With a template

await pm.sms.send({
  to:   '+2348012345678',
  from: 'SHUTTLERS',
  template: 'ride-arriving',
  variables: { driver_name: 'Chidi', eta: 3 },
});

Scheduled send

await pm.sms.send({
  to:   '+2348012345678',
  from: 'SHUTTLERS',
  body: 'Campaign launches at noon!',
  send_at: new Date('2026-05-01T12:00:00+01:00').toISOString(),
});
Cancel a scheduled send before it fires via POST /v1/sms/:id/cancel. After send_at the message status becomes queued and cancellation becomes a no-op (returns conflict).

With idempotency

Always pair sends with an idempotency key from your business data — see Idempotency:
await pm.sms.send(
  { to, from, body },
  `order-${orderId}-dispatch-sms`
);

Error cases

ErrorHTTPCause
phone_invalid400to not in E.164 format
sender_id_invalid400Sender too long, or rejected by carrier compliance
validation_error400Required field missing, body too long
sms_quota_exceeded402Monthly quota + wallet both exhausted
rate_limit_exceeded429Slow down and retry with backoff
Full catalog on Errors.