API Reference · v1

Documentation

The Twozero SMS API by Twozero lets you send messages, check delivery status and manage your account programmatically over HTTPS. Every response is JSON. Every send returns a receipt.

KYC verification required

Until your KYC is approved you can only send test messages to your own registered number. Complete verification from your dashboard to unlock full sending.

Quick start

  1. 01 Create an account at sms.twozero.io
  2. 02 Complete KYC verification for full access
  3. 03 Generate an API key from your dashboard
  4. 04 Send your first message with the API

Authentication

All requests are authenticated with an API key generated from your client dashboard. Keys are prefixed with sk_ followed by a 60-character string.

HTTP header (recommended)
X-API-Key: sk_your_api_key_here

API keys are accepted only via the X-API-Key request header.

Add a stable Idempotency-Key header to send requests so retries cannot create duplicate messages or charges. Keys may be up to 255 characters and must not be reused for a different request; conflicting reuse returns HTTP 409.

Base URL

All endpoints are relative to the production base URL:

Production
https://sms.twozero.io/api/v1

Rate limits

Requests are rate-limited per API key to ensure fair usage.

Endpoint Limit
Send SMS100 / minute
Send Bulk SMS10 / minute
Status / History / Balance300 / minute
POST

Send SMS

Send a single message to one recipient.

POST /api/v1/sms/send

Parameters

to string · required
Nepal phone number (+977XXXXXXXXXX, 977XXXXXXXXXX, or 10 digits).
message string · required
Message content, up to 1600 characters.
sender_id string · optional
Sender ID, up to 11 characters. Defaults to your account setting.

Example request

cURL
curl -X POST "https://sms.twozero.io/api/v1/sms/send" \
  -H "X-API-Key: sk_your_api_key_here" \
  -H "Idempotency-Key: order-123-message-1" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "9841234567",
    "message": "Hello! This is a test message.",
    "sender_id": "TZLABS"
  }'

Success · 200

200 OK
{
  "status": "success",
  "message": "SMS sent successfully",
  "data": {
    "message_id": "msg_abc123def456",
    "to": "9841234567",
    "credits_used": 1,
    "status": "sent"
  }
}

Error · 400

400 Bad Request
{
  "status": "error",
  "message": "Insufficient credits",
  "data": null
}
POST

Send bulk SMS

Queue the same message for many recipients and return immediately with a batch ID.

POST /api/v1/sms/send-bulk

Parameters

recipients array · required
Array of Nepal phone numbers, up to 1000 per request.
message string · required
Message content, up to 1600 characters.
sender_id string · optional
Sender ID, up to 11 characters.

Example request

cURL
curl -X POST "https://sms.twozero.io/api/v1/sms/send-bulk" \
  -H "X-API-Key: sk_your_api_key_here" \
  -H "Idempotency-Key: campaign-order-123" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": ["9841234567", "9851234567", "9861234567"],
    "message": "Special offer! Get 20% off today.",
    "sender_id": "TZLABS"
  }'

Accepted · 202

202 Accepted
{
  "status": "success",
  "message": "Bulk SMS accepted for processing.",
  "data": {
    "batch_id": "fcb19ba6-3ec7-44eb-86de-bbc21110c18a",
    "status": "queued",
    "total": 3,
    "processed": 0,
    "success": 0,
    "failed": 0,
    "estimated_credits": 3
  }
}

When provider balances cannot be fully verified, the response also carries a warnings array. The batch still dispatches and fails over between gateways.

Error · 402

402 Payment Required
{
  "status": "error",
  "message": "Provider capacity is short for this region.",
  "data": {
    "credits_needed": 36000,
    "provider_capacity_available": 16500
  }
}

Returned only when the region's known provider balances provably cannot cover the batch. Poll GET /api/v1/sms/batches/{batch_id} for progress.

GET

Message status

Check the delivery status of a sent message.

GET /api/v1/sms/status/{message_id}

Example request

cURL
curl -X GET "https://sms.twozero.io/api/v1/sms/status/msg_abc123def456" \
  -H "X-API-Key: sk_your_api_key_here"

Success · 200

200 OK
{
  "status": "success",
  "data": {
    "message_id": "msg_abc123def456",
    "recipient": "9841234567",
    "sender_id": "TZLABS",
    "status": "delivered",
    "credits_used": 1,
    "sent_at": "2026-01-15T10:30:00+05:45",
    "delivered_at": "2026-01-15T10:30:05+05:45",
    "delivery_report": {
      "status": "delivered",
      "description": "Delivered to handset",
      "reported_at": "2026-01-15T10:30:05+05:45"
    },
    "created_at": "2026-01-15T10:29:58+05:45"
  }
}
GET

Message history

Retrieve past messages with pagination and filtering.

GET /api/v1/sms/history

Query parameters

page (default 1) · per_page (default 50, max 100) · status · from_date · to_date

Example request

cURL
curl -X GET "https://sms.twozero.io/api/v1/sms/history?page=1&per_page=20&status=sent" \
  -H "X-API-Key: sk_your_api_key_here"
GET

Check balance

Return your current credit balance and KYC status.

GET /api/v1/account/balance

Example request

cURL
curl -X GET "https://sms.twozero.io/api/v1/account/balance" \
  -H "X-API-Key: sk_your_api_key_here"

Success · 200

200 OK
{
  "status": "success",
  "data": {
    "credits": 5000,
    "kyc_status": "approved",
    "kyc_verified": true
  }
}

PHP

send-sms.php
<?php

$apiKey  = 'sk_your_api_key_here';
$baseUrl = 'https://sms.twozero.io/api/v1';

function sendSms($to, $message, $senderId = null) {
    global $apiKey, $baseUrl;

    $data = ['to' => $to, 'message' => $message];
    if ($senderId) $data['sender_id'] = $senderId;

    $ch = curl_init($baseUrl . '/sms/send');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_POST => true,
        CURLOPT_HTTPHEADER => [
            'X-API-Key: ' . $apiKey,
            'Content-Type: application/json',
        ],
        CURLOPT_POSTFIELDS => json_encode($data),
    ]);

    $response = curl_exec($ch);
    curl_close($ch);

    return json_decode($response, true);
}

$result = sendSms('9841234567', 'Hello from Twozero!', 'TZLABS');
print_r($result);

JavaScript

send-sms.js
const API_KEY = 'sk_your_api_key_here';
const BASE_URL = 'https://sms.twozero.io/api/v1';

async function sendSms(to, message, senderId = null) {
    const data = { to, message };
    if (senderId) data.sender_id = senderId;

    const response = await fetch(`${BASE_URL}/sms/send`, {
        method: 'POST',
        headers: {
            'X-API-Key': API_KEY,
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
    });

    return await response.json();
}

const result = await sendSms('9841234567', 'Hello from Twozero!', 'TZLABS');
console.log(result);

Python

send_sms.py
import requests

API_KEY = 'sk_your_api_key_here'
BASE_URL = 'https://sms.twozero.io/api/v1'

headers = {
    'X-API-Key': API_KEY,
    'Content-Type': 'application/json',
}

def send_sms(to: str, message: str, sender_id: str = None) -> dict:
    data = {'to': to, 'message': message}
    if sender_id:
        data['sender_id'] = sender_id

    response = requests.post(f'{BASE_URL}/sms/send', headers=headers, json=data)
    return response.json()

result = send_sms('9841234567', 'Hello from Twozero!', 'TZLABS')
print(result)

Error codes

Code Meaning Description
200 OK Request successful
400 Bad Request Invalid request, e.g. insufficient credits
401 Unauthorized Missing or invalid API key
403 Forbidden Account inactive or IP not whitelisted
404 Not Found Resource not found
409 Conflict Idempotency key was reused for different request data
422 Validation Error Request data failed validation
429 Too Many Requests Rate limit exceeded
500 Server Error Internal server error

Message status codes

pending
Message queued and waiting to be sent
sent
Message handed off to the gateway
delivered
Message delivered to the recipient
failed
Message delivery failed
rejected
Message rejected by the gateway

Need a hand?

Stuck on an integration or have a question about the API?