API Documentation
The Sahla SMS API is a REST API over HTTPS. Every request is authenticated with an API key and returns JSON. Base URL:
https://sms.sahlapay.dz/api/public/v1
Quick start
Pair an Android device in your dashboard, create an API key, then send your first message. The device ID is optional — Sahla SMS automatically selects an online device when you omit it.
1curl -X POST https://sms.sahlapay.dz/api/public/v1/send-sms \2 -H "Content-Type: application/json" \3 -H "x-api-key: $SAHLA_API_KEY" \4 -d '{5 "recipients": ["+1234567890"],6 "message": "Hello from Sahla SMS!"7 }'Authentication
Pass your API key in the x-api-key header on every request. Keys are shown once when created — store them securely on your server and never expose them in browser code.
x-api-key: sk_live_3f9a...c21dKeys can be limited to sending SMS, reading SMS, reading devices, and managing webhooks. Revoking a key takes effect immediately.
Send a single SMS
POST/send-sms
1{2 "recipients": ["+1234567890"],3 "message": "Your verification code is 481932",4 "deviceId": "dev_8c21f0" // optional5}1{2 "success": true,3 "data": {4 "messageId": "msg_7b12ce",5 "status": "queued",6 "segments": 1,7 "recipients": 1,8 "queuedAt": "2026-01-14T09:21:44Z"9 }10}Send bulk SMS
POST/send-sms
Pass up to 1,000 recipients per request, or use a saved contact group. Messages are queued and sent steadily by your device with a short pause between each.
1{2 "recipients": ["+1234567890", "+212612345678"],3 "groupId": "grp_4a91bd", // optional, merged with recipients4 "message": "Hi {{name}}, your order has shipped.",5 "variables": { "name": "Sam" }6}1{2 "success": true,3 "data": {4 "batchId": "bat_19fd03",5 "queued": 2,6 "rejected": 0,7 "estimatedCompletion": "2026-01-14T09:24:10Z"8 }9}List devices
GET/devices
1{2 "success": true,3 "data": [4 {5 "id": "dev_8c21f0",6 "name": "Pixel 6a",7 "phoneNumber": "+1234567890",8 "status": "online",9 "batteryLevel": 87,10 "signalStrength": 4,11 "lastSeenAt": "2026-01-14T09:21:02Z",12 "messagesSent": 184213 }14 ]15}Message status
GET/message-status
A message moves through queued, sent, then delivered. A failed delivery returns failed with an error reason.
1{2 "success": true,3 "data": {4 "id": "msg_7b12ce",5 "recipient": "+1234567890",6 "status": "delivered",7 "segments": 1,8 "queuedAt": "2026-01-14T09:21:44Z",9 "sentAt": "2026-01-14T09:21:47Z",10 "deliveredAt": "2026-01-14T09:21:52Z"11 }12}Receive SMS
GET/devices
Enable SMS receiving in the Android app, then retrieve incoming messages or subscribe to the sms.received webhook for real-time delivery.
Webhooks
Register a webhook URL in the dashboard and select the events you need. Every request includes an x-sahla-signature header containing an HMAC-SHA256 signature of the raw body using your signing secret.
1{2 "event": "sms.delivered",3 "timestamp": "2026-01-14T09:21:52Z",4 "data": {5 "messageId": "msg_7b12ce",6 "deviceId": "dev_8c21f0",7 "recipient": "+1234567890",8 "status": "delivered"9 }10}1import { createHmac, timingSafeEqual } from 'crypto'2 3const expected = createHmac('sha256', process.env.SIGNING_SECRET)4 .update(rawBody)5 .digest('hex')6 7const ok = timingSafeEqual(8 Buffer.from(signatureHeader),9 Buffer.from(expected),10)Failed deliveries are retried with increasing delays for up to 24 hours. Respond with any 2xx status within 10 seconds to acknowledge receipt.
Errors & rate limits
Errors return a non-2xx status with a JSON body. The API allows 60 requests per minute per key; exceeding this returns 429 with a Retry-After header.
1{2 "success": false,3 "error": {4 "code": "invalid_recipient",5 "message": "Recipient +12345 is not a valid E.164 phone number"6 }7}401 unauthorized— API key is missing, revoked, or malformed403 insufficient_scope— the key lacks the required permission409 no_device_available— no paired device is currently online422 quota_exceeded— the monthly plan limit has been reached