opensms :: docs
$ send sms
Create an SMS job with your API key. A paired gateway claims it and reports the outcome.
## create a message
POST /api/v1/messages — API key auth. The response is 202 Accepted.
curl -X POST https://opensms.dev/api/v1/messages \
-H "Authorization: Bearer opensms_xxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"to": "+923001234567", "message": "Hello from OpenSMS"}'{
"id": "b3f1...",
"status": "pending"
}## routing
By default OpenSMS selects an available gateway and SIM belonging to the API key's owner. You can optionally target a specific device and/or SIM. Both are validated against your account — cross-account access is rejected.
curl -X POST https://opensms.dev/api/v1/messages \
-H "Authorization: Bearer opensms_xxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"to": "+923001234567",
"message": "Routed through a specific phone and SIM",
"deviceId": "e2c1...",
"simId": "a1b2..."
}'## check status
GET /api/v1/messages/:id — API key auth.
curl https://opensms.dev/api/v1/messages/b3f1... \
-H "Authorization: Bearer opensms_xxxxxxxxx"{
"id": "b3f1...",
"to": "+923001234567",
"status": "sent",
"error": null,
"failureKind": null,
"attempts": 1,
"deviceId": "e2c1...",
"simId": "a1b2...",
"createdAt": "2026-09-18T10:00:00.000Z",
"sentAt": "2026-09-18T10:00:04.000Z",
"failedAt": null
}## job lifecycle
pending → processing → sent or failed. The attempts counter shows how many times a gateway has claimed the job.
## failures and fallback
When a gateway reports a failure it includes an error message, and the job is marked with a failureKind:
confirmed— the gateway explicitly reported the SMS was not sent.ambiguous— the gateway claimed the job but never reported an outcome. It may already have been sent.unavailable— the target was unavailable before dispatch.
Automatic retry is off by default. Only confirmed failures can ever be retried, and never ambiguous ones, to avoid sending the same SMS twice.