integration reference · live document

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.

01 · authentication

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
02 · live routes

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)SlotCarrierHourly capStatus
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.

03 · endpoints

The platform API surface

POST /api/v1/messages

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
GET /api/v1/messages?id=N

Fetch one message (status polling).

GET /api/v1/messages

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
POST /api/v1/messages?id=N&action=cancel

Cancel a message that is still queued (pending/pushed). Already-sending messages cannot be canceled.

GET /api/v1/status

Preflight: 24h queue counts for your account, your default route with online state, and the number of online devices.

GET /api/v1/inbound

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
04 · message lifecycle

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"}
05 · webhooks

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.

06 · status codes

What the gateway answers

CodeMeaning
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