curl --request POST \
--url https://api.robase.dev/v1/sms/send \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"phone_number": "+2348012345678",
"message": "Your order #12345 has been shipped.",
"metadata": {}
}
'import requests
url = "https://api.robase.dev/v1/sms/send"
payload = {
"phone_number": "+2348012345678",
"message": "Your order #12345 has been shipped.",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
phone_number: '+2348012345678',
message: 'Your order #12345 has been shipped.',
metadata: {}
})
};
fetch('https://api.robase.dev/v1/sms/send', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.robase.dev/v1/sms/send",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'phone_number' => '+2348012345678',
'message' => 'Your order #12345 has been shipped.',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.robase.dev/v1/sms/send"
payload := strings.NewReader("{\n \"phone_number\": \"+2348012345678\",\n \"message\": \"Your order #12345 has been shipped.\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.robase.dev/v1/sms/send")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"phone_number\": \"+2348012345678\",\n \"message\": \"Your order #12345 has been shipped.\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.robase.dev/v1/sms/send")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"phone_number\": \"+2348012345678\",\n \"message\": \"Your order #12345 has been shipped.\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_bodySend an SMS
POST /v1/sms/send — transactional message, same routing and credits as OTP.
curl --request POST \
--url https://api.robase.dev/v1/sms/send \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"phone_number": "+2348012345678",
"message": "Your order #12345 has been shipped.",
"metadata": {}
}
'import requests
url = "https://api.robase.dev/v1/sms/send"
payload = {
"phone_number": "+2348012345678",
"message": "Your order #12345 has been shipped.",
"metadata": {}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
phone_number: '+2348012345678',
message: 'Your order #12345 has been shipped.',
metadata: {}
})
};
fetch('https://api.robase.dev/v1/sms/send', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.robase.dev/v1/sms/send",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'phone_number' => '+2348012345678',
'message' => 'Your order #12345 has been shipped.',
'metadata' => [
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.robase.dev/v1/sms/send"
payload := strings.NewReader("{\n \"phone_number\": \"+2348012345678\",\n \"message\": \"Your order #12345 has been shipped.\",\n \"metadata\": {}\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.robase.dev/v1/sms/send")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"phone_number\": \"+2348012345678\",\n \"message\": \"Your order #12345 has been shipped.\",\n \"metadata\": {}\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.robase.dev/v1/sms/send")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"phone_number\": \"+2348012345678\",\n \"message\": \"Your order #12345 has been shipped.\",\n \"metadata\": {}\n}"
response = http.request(request)
puts response.read_bodyAuthorizations
Your Robase API key. Starts with robe_. Include as Authorization: Bearer robe_...
Headers
Opaque client-generated key. Replaying the same key within 24 hours
returns the original response (with Idempotent-Replayed: true)
instead of performing the action again. Recommended for every send so
a network-level retry cannot double-charge. The same key with a
different endpoint or body returns 422 idempotency_key_reused; a
repeat while the first request is still running returns
409 request_in_progress. 5xx and 429 responses are not kept, so
a retry with the same key runs again.
255Body
Phone number in E.164 format
"+2348012345678"
SMS message body. The limit is six SMS segments, not a character count: a carrier splits a long message into parts and bills each one, and how many characters fit in a part depends on the alphabet the message needs — 160 per part in GSM-7 (153 once it is split), but 70 (then 67) as soon as one character forces UCS-2. So the practical ceiling is 918 plain-Latin characters, or 402 in a script that needs UCS-2.
"Your order #12345 has been shipped."
Arbitrary key-value data attached to the message
Response
SMS created, charged, and queued for delivery
SMS message ID
Phone number the SMS was sent to
ISO 3166-1 alpha-2 country code
Credits consumed: the country's rate multiplied by segments, since
a carrier bills each part of a split message as its own send.
Initial status — always pending; transitions to
sent/delivered/failed asynchronously, or to blocked if anti-spam
screening stops it before dispatch (the credit is then refunded).
pending How many SMS parts the message was split into, and therefore the multiple of the country's rate it was charged at.
1
The alphabet the message needed, which is what decided the part
size: 160 characters per part in gsm7, 70 in ucs2. A single
character outside the GSM alphabet moves the whole message to
ucs2.
gsm7, ucs2 Whether the body was rewritten before it was measured. With the
workspace's sanitize_symbols setting on (the default), characters
GSM-7 cannot carry are replaced with plain equivalents — ₦
becomes NGN, curly quotes straighten — and anything with no
equivalent, such as an emoji, is removed. Letters are never
removed, and the rewrite is dropped whenever it would not lower
the part count. Turn the setting off to have bodies delivered
exactly as sent.