Examples
Every example below does the same thing — sends one SMS through the gateway — so you can lift the
one that matches your stack. Replace <phone-ip> with the address the app shows after you tap
Start, and the sk_local_... value with your API key.
The app can also generate these for you: its Copy example menu produces ready-to-run snippets for cURL, C#, Node.js, and Flutter, already filled in with your live URL and key.
cURL
curl -X POST http://<phone-ip>:8080/api/sms/send \
-H "Authorization: Bearer sk_local_xxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"to":"09171234567","message":"Hello from Hiras"}'
Add "simSlot": 2 to the body to send from a specific SIM on a multi-SIM phone.
Node.js
const res = await fetch("http://<phone-ip>:8080/api/sms/send", {
method: "POST",
headers: {
"Authorization": "Bearer sk_local_xxxxxxxxxxxxxxxxxxxxxxxx",
"Content-Type": "application/json",
},
body: JSON.stringify({ to: "09171234567", message: "Hello from Hiras" }),
});
const data = await res.json();
if (!data.success) throw new Error(data.error?.message ?? "send failed");
console.log(data.status); // "queued"
C#
using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization =
new("Bearer", "sk_local_xxxxxxxxxxxxxxxxxxxxxxxx");
var payload = new { to = "09171234567", message = "Hello from Hiras" };
var res = await http.PostAsJsonAsync(
"http://<phone-ip>:8080/api/sms/send", payload);
res.EnsureSuccessStatusCode();
var body = await res.Content.ReadFromJsonAsync<JsonElement>();
Console.WriteLine(body.GetProperty("status").GetString()); // "queued"
Flutter
import 'package:http/http.dart' as http;
import 'dart:convert';
final res = await http.post(
Uri.parse('http://<phone-ip>:8080/api/sms/send'),
headers: {
'Authorization': 'Bearer sk_local_xxxxxxxxxxxxxxxxxxxxxxxx',
'Content-Type': 'application/json',
},
body: jsonEncode({'to': '09171234567', 'message': 'Hello from Hiras'}),
);
final data = jsonDecode(res.body);
if (data['success'] != true) {
throw Exception(data['error']?['message'] ?? 'send failed');
}
print(data['status']); // "queued"
What a success looks like
All four return the same envelope:
{
"success": true,
"mode": "real",
"smsSent": true,
"messageId": "msg_...",
"status": "queued",
"segments": 1
}
status: "queued" means Android has accepted the message for sending — it later becomes sent or
failed. It is not a carrier delivery receipt. Check a message’s outcome with
GET /api/messages/:id.
Testing without spending a text
Turn on Dry Run and every example above returns a realistic
response with "mode": "dry-run" and "smsSent": false — no SIM, no load. Turn on
Failure Simulation to make them return a specific
error so you can test your failure path.