SMS Web

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.

Create an account to get your own API key and free starter credits, or sign in.
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

https://simsms.rongoit.com/api.php?action=send

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-Evente.g. message.sent
X-Webhook-Idthe message id
X-Webhook-Signaturesha256=<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

https://simsms.rongoit.com/api.php?action=device/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

https://simsms.rongoit.com/api.php?action=device/poll

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

https://simsms.rongoit.com/api.php?action=device/ack

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" }