Send and receive SMS over real phones
Everything on this page is generated from the gateway's current configuration —
the routes below exist right now. AI agents and tooling should ingest
/llms.txt, the machine-readable version
of this page.
Every request carries an API key
Send your account's key (issued in the gateway console) in the
X-API-Key header. Responses are JSON:
{"status", "message", "data"}.
SMSGW_API_BASE=https://smsgateway.ddg.mx/api/v1
SMSGW_API_KEY=sg_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Which number a message goes out on
Every SIM in the gateway is listed below, one row per slot. Pass a route label
as the sim field when sending to pick the outbound number,
"any" for least-loaded, or omit it for your account default.
Unlabeled SIMs can't be targeted directly but still carry
"any"/default traffic.
0 devices online · offline after 20 min without a heartbeat
Route (sim value) | Slot | Carrier | Hourly cap | Status |
|---|---|---|---|---|
unlabeled — via "any"/default only |
0 | T-Mobile | 120/hr | device offline |
bg-primary |
1 | T-Mobile | 120/hr | device offline |
Resolution order: explicit sim (label, then phone number — unknown
routes fail with 422), account default (unavailable also fails with
422), then "any" picks the route with the most hourly
headroom on an online device. Per-route caps protect numbers from carrier
spam-flagging; when everything is at cap or offline, sends return 503.
The platform API surface
Enqueue an outbound SMS. Returns 201 with the message row, or 200 replaying the original when client_ref matches a prior send (idempotent).
to- required — destination number, E.164 (bare 10-digit US numbers are auto-prefixed +1)
body- required — message text; long bodies are split into parts automatically
sim- optional — a route label from the routes table, a route phone number, or "any" for least-loaded; omit for the account default
client_ref- optional — idempotency key (max 64 chars); re-POSTing the same value returns the original message instead of sending twice
Fetch one message (status polling).
List messages, newest first, paged.
status- optional — filter: pending|pushed|sending|sent|delivered|failed|canceled
to- optional — filter by destination number
since- optional — created_at >= this datetime (server time, America/New_York)
page- optional — 1-based page number
per_page- optional — default 50, max 200
Cancel a message that is still queued (pending/pushed). Already-sending messages cannot be canceled.
Preflight: 24h queue counts for your account, your default route with online state, and the number of online devices.
Pull-style inbound SMS list for your account (push-style delivery happens via your webhook), newest first, paged.
since- optional — created_at >= this datetime
from- optional — filter by sender number
page- optional — 1-based page number
per_page- optional — default 50, max 200
From enqueue to delivery receipt
Failed or canceled messages exit the flow with failed /
canceled. Poll GET /api/v1/messages?id=N or subscribe
to status webhook events. Always send a client_ref on
transactional messages — retrying the same reference can never double-send.
POST /api/v1/messages
X-API-Key: sg_…
Content-Type: application/json
{"to": "+15551234567", "body": "Your code is 123456", "sim": "any", "client_ref": "otp-9f83a1"}
Inbound SMS and status events, pushed to you
Set a webhook URL + signing secret on your account for push delivery of
inbound and status events. Verify
X-SG-Signature — HMAC-SHA256 of the raw body — before trusting a
payload:
$raw = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $raw, $_ENV['SMSGW_WEBHOOK_SECRET']);
if (!hash_equals($expected, $_SERVER['HTTP_X_SG_SIGNATURE'] ?? '')) {
http_response_code(401); exit;
}
Return 2xx quickly. Non-2xx deliveries retry with backoff
(1m, 5m, 15m, 1h, 6h); exhausted deliveries are marked failed and visible in the
console. Prefer pull? GET /api/v1/inbound?since=… works without a
webhook.
What the gateway answers
| Code | Meaning |
|---|---|
| 200 | OK (idempotent replay on send; success on reads) |
| 201 | Message created |
| 401 | Invalid or missing X-API-Key |
| 404 | Not found (or not your account's resource) |
| 405 | Method not allowed |
| 422 | Invalid number, empty body, or unknown/disabled route |
| 429 | Account daily quota exceeded |
| 503 | No online device/SIM available |