📚 API Documentation

DevSMS API

RESTful API for SMS sending

Base URL

https://devsms.uz/api

Important:

All API requests require Authorization: Bearer {token} header.

🔐 Authentication

Each request must include the following header:

Authorization: Bearer your_token_here
POST

1. Send SMS

https://devsms.uz/api/send_sms.php

Request Body:

{
    "phone": "998901234567",
    "message": "Test SMS xabari",
    "from": "4546",
    "callback_url": "https://your-domain.com/sms-callback"
}

Parameters:

Parameter Type Required Description
phone string Yes Phone number (998901234567)
message string Yes SMS message text
from string No From (default: 4546)
callback_url string No URL to receive SMS status updates (http:// or https://)
type string No SMS type: eskiz (default), simple, universal_otp

Response:

// To Uzbekistan number
{
    "success": true,
    "message": "SMS muvaffaqiyatli yuborildi",
    "data": {
        "sms_id": 123,
        "request_id": "uuid-here",
        "status": "sent",
        "parts_count": 1,
        "total_cost": "$0.005",
        "balance": "$0.079",
        "type": "eskiz"
    }
}
POST

1.1 Universal OTP SMS

https://devsms.uz/api/send_sms.php

Send verification codes using Eskiz-approved universal OTP templates. Company name is checked by AI moderation.

Universal templates are pre-approved by Eskiz. You only provide the company name and OTP code. If the company name is inappropriate, the SMS is NOT sent and your balance is NOT charged (the response returns charged: false). Abuse protection: after 20 CONSECUTIVE rejections, universal OTP is suspended for 24 hours — the counter resets to zero as soon as one name passes moderation. Every response includes reject_streak and remaining_attempts.

Request Body:

{
    "phone": "998901234567",
    "type": "universal_otp",
    "template_type": 1,
    "service_name": "TechShop",
    "otp_code": "5678",
    "callback_url": "https://your-site.com/callback"
}

Parameters:

Parameter Type Required Description
phone string Yes Phone number (998901234567)
type string Yes "universal_otp"
template_type integer Yes Template type: 1=Operation verification, 2=Password reset, 3=Registration, 4=Login
service_name string Yes Company/service name (2-50 chars, letters, numbers, spaces, dots, hyphens only)
otp_code string Yes OTP verification code (4-8 digits)
callback_url string No URL to receive SMS status updates (http:// or https://)

About callbacks: a status callback is delivered only when the SMS was ACTUALLY sent to Eskiz. If the company name fails AI moderation, no SMS is sent and no request_id is created — in that case no callback arrives. That is exactly what charged: false in the response means.

Available templates:

1. MyService tizimi: {service_name} xizmatida amaliyotni tasdiqlash kodi: {otp_code}
2. MyService tizimi: {service_name} xizmatida parolni tiklash uchun tasdiqlash kodi: {otp_code}
3. MyService tizimi: {service_name} xizmatiga ro'yxatdan o'tish uchun tasdiqlash kodi: {otp_code}
4. MyService tizimi: {service_name} xizmatiga kirish uchun tasdiqlash kodi: {otp_code}

Response:

{
    "success": true,
    "message": "SMS muvaffaqiyatli yuborildi",
    "data": {
        "sms_id": 456,
        "request_id": "uuid-here",
        "status": "sent",
        "parts_count": 1,
        "total_cost": "$0.005",
        "balance": "$0.079",
        "type": "universal_otp"
    }
}

Blocked SMS response:

{
    "success": false,
    "error": "Korxona nomi nomaqbul deb topildi: ... SMS yuborilmadi, lekin to'lov yechildi."
}
GET

2. Get SMS History

https://devsms.uz/api/get_history.php

Query Parameters:

Parameter Type Default Description
limit integer 50 Number of SMS (max: 200)
offset integer 0 Offset
status string null Status filter (sent, delivered, failed)

Example:

GET https://devsms.uz/api/get_history.php?limit=10&offset=0&status=delivered

Response:

{
    "success": true,
    "data": {
        "history": [
            {
                "id": 123,
                "phone_number": "998901234567",
                "message": "Salom!",
                "status": "delivered",
                "parts_count": 1,
                "total_cost": "$0.005",
                "from_number": "4546",
                "eskiz_request_id": "uuid-here",
                "eskiz_message_id": "msg-id",
                "sent_at": "2026-03-09 10:30:00",
                "delivered_at": "2026-03-09 10:30:05",
                "failed_at": null,
                "created_at": "2026-03-09 10:29:58"
            }
        ],
        "count": 1,
        "limit": 10,
        "offset": 0
    }
}

Status Timestamps

Parameter Description
created_at Time SMS was created
sent_at Time SMS was sent
delivered_at Time SMS was delivered
failed_at Time SMS failed
GET

3. Get Balance

https://devsms.uz/api/get_balance.php

Response:

{
    "success": true,
    "data": {
        "balance": "$0.083",
        "sms_price": "$0.005",
        "statistics": {
            "total_sms": 100,
            "total_spent": "$0.414",
            "today_sms": 10,
            "today_spent": "$0.042",
            "month_sms": 50,
            "month_spent": "$0.207"        }
    }
}
GET

4. Get SMS Status

https://devsms.uz/api/get_status.php

Query Parameters:

Parameter Type Description
sms_id integer SMS ID (database ID)
request_id string Eskiz request ID

Example:

GET https://devsms.uz/api/get_status.php?sms_id=123

or

GET https://devsms.uz/api/get_status.php?request_id=uuid-here

Response:

{
    "success": true,
    "data": {
        "id": 123,
        "phone_number": "998901234567",
        "message": "Salom!",
        "status": "delivered",
        "parts_count": 1,
        "total_cost": "$0.005",
        "from_number": "4546",
        "eskiz_request_id": "uuid-here",
        "eskiz_message_id": "msg-id",
        "sent_at": "2026-03-09 10:30:00",
        "delivered_at": "2026-03-09 10:30:05",
        "failed_at": null,
        "created_at": "2026-03-09 10:29:58",
        "updated_at": "2026-03-09 10:30:05"
    }
}

🔔 Callback URL

When you include the callback_url parameter when sending an SMS, a POST request will be sent to your URL when the SMS status changes (sent, delivered, failed).

When callback is sent:

When SMS is sent (sent)
When SMS is delivered (delivered)
When SMS fails (failed)

Data sent to your URL:

{
    "sms_id": 123,
    "request_id": "uuid-here",
    "phone": "998901234567",
    "status": "delivered",
    "sent_at": "2026-03-09 10:30:00",
    "delivered_at": "2026-03-09 10:30:05",
    "failed_at": null,
    "timestamp": "2026-03-09 10:30:05"
}

Parameters:

Parameter Type Description
sms_id integer SMS ID (database ID)
request_id string Eskiz request ID
phone string Phone number (998901234567)
status string Status filter (sent, delivered, failed)
sent_at string|null Time SMS was sent
delivered_at string|null Time SMS was delivered
failed_at string|null Time SMS failed
timestamp string Time SMS was created

Note: Callback is sent with a 5 second timeout. If your server does not respond, no retry is attempted.

✅ callback_url requirements

For security, callback_url is validated twice: when the SMS is submitted, and again at the moment the callback is delivered. The following are rejected:

  • Any scheme other than http:// or https://
  • Internal and reserved IP ranges (127.0.0.1, 10.x, 172.16-31.x, 192.168.x, 169.254.x, ::1 and others)
  • localhost and test/placeholder domains (example.com, test.com and similar)
  • Domains that do not resolve in DNS
  • URLs longer than 500 characters

At delivery time the host is re-validated and pinned to the confirmed IP address (DNS-rebinding protection). Redirects are not followed, the response is capped at 10 KB, and it is never returned to you.

🔐 Verifying callback authenticity (signature)

Every callback is sent with two additional headers. They prove the request genuinely came from DevSMS — without them, anyone who knows your callback URL could post a forged status.

X-DevSMS-Timestamp: 1786500000
X-DevSMS-Signature: sha256=9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08

Your signing key is in your cabinet: Settings → API. Never share it.

How to verify:

  1. Check that X-DevSMS-Timestamp is within 5 minutes of the current time (replay protection).
  2. Compute HMAC-SHA256 with your webhook key over the string "{timestamp}.{raw_body}".
  3. Compare the result to X-DevSMS-Signature using hash_equals (constant-time comparison).
<?php
// XOM body — json_decode qilmasdan!
$rawBody   = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_DEVSMS_SIGNATURE'] ?? '';
$timestamp = $_SERVER['HTTP_X_DEVSMS_TIMESTAMP'] ?? '';
$secret    = 'whsec_...'; // kabinetdagi kalitingiz

if (!is_numeric($timestamp) || abs(time() - (int)$timestamp) > 300) {
    http_response_code(403); exit('stale');
}

$expected = 'sha256=' . hash_hmac('sha256', $timestamp . '.' . $rawBody, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(403); exit('bad signature');
}

// Imzo to'g'ri — endi ma'lumotga ishonish mumkin
$data = json_decode($rawBody, true);

IMPORTANT: the signature is computed over the RAW request body. Do not parse the JSON and re-encode it — key order will change and the signature will not match.

Nothing changed for existing integrations: the payload is unchanged and the headers are purely additive. You can add verification whenever you are ready.

📝 SMS Statuses

Status Description
pending SMS not yet sent (pending)
sent SMS sent (accepted by Eskiz)
delivered SMS delivered to recipient
failed SMS failed (rejected or undeliverable)

❌ Errors

When an error occurs, the following format is returned:

{
    "success": false,
    "error": "Xatolik xabari"
}

HTTP Status Codes:

Code Description
200 Success
400 Bad Request
401 Authentication Error
403 Forbidden
404 Not Found
500 Server Error

Tip:

You can use Postman or cURL to test the API.

🔧 cURL Examples

Send SMS:

curl -X POST https://devsms.uz/api/send_sms.php \
  -H "Authorization: Bearer your_token" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "998901234567",
    "message": "Test SMS"
  }'

Get Balance:

curl -X GET https://devsms.uz/api/get_balance.php \
  -H "Authorization: Bearer your_token"

💻 Code Examples

Select programming language:

<?php
// DevSMS API - PHP Example

$token = "your_api_token_here";
$baseUrl = "https://devsms.uz/api";

// SMS Yuborish
function sendSMS($token, $baseUrl, $phone, $message) {
    $ch = curl_init("$baseUrl/send_sms.php");
    
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            "Authorization: Bearer $token",
            "Content-Type: application/json"
        ],
        CURLOPT_POSTFIELDS => json_encode([
            "phone" => $phone,
            "message" => $message
        ])
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    return json_decode($response, true);
}

// Balansni olish
function getBalance($token, $baseUrl) {
    $ch = curl_init("$baseUrl/get_balance.php");
    
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HTTPHEADER => [
            "Authorization: Bearer $token"
        ]
    ]);
    
    $response = curl_exec($ch);
    curl_close($ch);
    
    return json_decode($response, true);
}

// Ishlatish
$result = sendSMS($token, $baseUrl, "998901234567", "Salom!");
print_r($result);

$balance = getBalance($token, $baseUrl);
print_r($balance);
?>