API Documentation
REST API for sending SMS through your registered gateway phones. Authenticate with your personal API key — no device code needed; the server routes each message to one of your connected phones.
| Base URL | https://simsms.rongoit.com/api.php |
| Auth (send) | Header X-Api-Key — your personal key |
| Auth (device) | Header X-Device-Token — a device login code (used by the app) |
| Billing | 1 credit per SMS. Failed sends are refunded automatically. |
| Delivery status | Pass webhook_url when sending — we call it with the final status.
See Webhooks → |
| Your API key | Register to get one. |
| Postman | Download collection ↓
(set base_url and api_key) |
Send endpoint
POSTSend an SMS
Queues a message and charges 1 credit. One of your connected phones
sends it (never two). The SIM is chosen in the gateway app — not in the request.
Pass an optional webhook_url to be notified of the final status
(see Webhooks below).
curl -X POST "https://simsms.rongoit.com/api.php?action=send" \
-H "X-Api-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"to": "01700000000",
"message": "Hello from SMS Web",
"webhook_url": "https://your-site.com/sms-webhook"
}'
// 201 Created
{ "status": "ok", "id": 12, "to": "01700000000", "cost": 1, "credits_left": 9, "webhook": true, "queued": true }
webhook_url is optional — omit it for no callback. It must be a
public http(s) URL. webhook in the response echoes whether a callback was registered.
Errors: 401 invalid key · 402 insufficient credits ·
403 suspended · 409 no device connected · 422 missing fields / bad webhook_url.
Webhooks — delivery status
How it works
Add webhook_url to a send request. When one of your gateway phones actually sends the
message (or fails to), we POST a JSON status to that URL. This is how your site learns the outcome —
the send response only tells you the message was queued, not delivered.
The callback fires once, on the final status the phone reports:
message.sent, message.failed (and message.delivered if a phone
reports a delivery receipt). Requests are POST with Content-Type: application/json.
Request headers
X-Webhook-Event | e.g. message.sent |
X-Webhook-Id | the message id |
X-Webhook-Signature | sha256=<hmac> — HMAC-SHA256 of the raw body, keyed with your API key |
Payload
POST https://your-site.com/sms-webhook
X-Webhook-Event: message.sent
X-Webhook-Id: 12
X-Webhook-Signature: sha256=9f86d08188...
{
"event": "message.sent",
"id": 12,
"to": "01700000000",
"status": "sent",
"error": null,
"sim": 1,
"cost": 1,
"timestamp": "2026-09-01T12:00:00+06:00"
}
status is one of sent, failed,
delivered. On a failure, error holds the reason and the credit is refunded.
sim is the SIM the phone used (may be null).
Verify the signature
Always verify X-Webhook-Signature before trusting the body.
The secret is your API key. Sign the raw request body, byte-for-byte.
// PHP
$payload = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $payload, 'YOUR_API_KEY');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
if (!hash_equals($expected, $signature)) {
http_response_code(403);
exit;
}
$data = json_decode($payload, true);
// … update your record for $data['id'] with $data['status'] …
http_response_code(200); // acknowledge fast
// Node.js (Express — use the RAW body, e.g. express.raw({type:'*/*'}))
const crypto = require('crypto');
const expected = 'sha256=' +
crypto.createHmac('sha256', 'YOUR_API_KEY').update(req.body).digest('hex');
const sig = req.headers['x-webhook-signature'] || '';
if (sig.length !== expected.length ||
!crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(403).end();
}
res.status(200).end(); // acknowledge fast, then process
Retries & reliability
Respond with a 2xx status as soon as you receive the event; do any slow work afterwards.
If your endpoint returns a non-2xx status or times out, we retry automatically every few
minutes, up to a handful of attempts. Because of retries an event may arrive more than once — treat it
idempotently, keyed on id.
Your URL must be publicly reachable over http(s); loopback and private addresses are rejected.
Use HTTPS so the payload and signature can't be read in transit.
Device endpoints — used by the Android app
POSTDevice login
curl -X POST "https://simsms.rongoit.com/api.php?action=device/login" \
-H "Content-Type: application/json" \
-d '{ "code": "DEVICE_CODE" }'
// 200 OK
{ "status": "ok", "device": { "id": 1, "name": "Office Pixel", "phone_number": null } }
GETPoll pending messages
Returns the owner's pending messages and claims them (marks queued) so no other phone of the same user sends the same message. sim is null — the app chooses which SIM to send from.
curl "https://simsms.rongoit.com/api.php?action=device/poll" \ -H "X-Device-Token: DEVICE_CODE"
// 200 OK
{ "status": "ok", "messages": [ { "id": 12, "to": "01700000000", "message": "Hello", "sim": null } ] }
POSTAcknowledge result
status: sent, delivered, or failed. A failed ack refunds the credit. sim records the SIM the phone actually used. If the original send had a webhook_url, a terminal ack fires that webhook.
curl -X POST "https://simsms.rongoit.com/api.php?action=device/ack" \
-H "X-Device-Token: DEVICE_CODE" \
-H "Content-Type: application/json" \
-d '{ "id": 12, "status": "sent", "sim": 1, "error": null }'
// 200 OK
{ "status": "ok", "id": 12, "result": "sent" }