SIM-Powered OTP &
Transactional SMS Engine.
Eliminate expensive 3rd-party aggregator markups (৳0.35 - ৳0.50 per SMS). SwapnoPay turns your Android device and carrier SIM cards (GP, Banglalink, Robi, Teletalk) into a secure, ultra-low-latency, zero-cost cellular SMS dispatch engine for websites, e-commerce, and mobile apps.
Platform Mechanism & Architecture
SwapnoPay's cellular gateway bridges cloud HTTP REST APIs with physical Android handset SIM hardware over resilient WebSockets and background polling.
Unlike SMS aggregators that charge ৳0.30 to ৳0.55 per message, SwapnoPay dispatches via your Android phone's unlimited carrier SMS bundles (e.g. 1000 SMS for ৳25), slashing communication costs by 95%+.
Incoming API requests immediately fire real-time WebSocket events (sms_gateway_dispatch) to your connected Android phone. If connectivity flutters, the device polls /device/pending automatically.
Built-in CSPRNG 4-8 digit numeric code generation, configurable TTL expiry (default 5 mins), automatic background garbage cleanup, and 5-attempt anti-brute-force lockout protection.
System Sequence & Flowchart
End-to-end cellular dispatch pipeline from external website request to Android SIM transmission and delivery receipt.
┌────────────────────┐ ┌──────────────────────┐ ┌────────────────────────┐ ┌────────────────────┐
│ Client Website / │ │ SwapnoPay Backend │ │ Merchant Android Phone │ │ Customer Mobile │
│ E-Commerce App │ │ (REST API + WS Core) │ │ (Cellular SIM Worker) │ │ (End-User Device) │
└─────────┬──────────┘ └──────────┬───────────┘ └───────────┬────────────┘ └─────────┬──────────┘
│ │ │ │
│ 1. POST /send-otp or /send │ │ │
│ (x-api-key: sp_gw_m_...) │ │ │
├───────────────────────────────>│ │ │
│ │ 2. Cryptographic Code Gen │ │
│ │ Enqueue Job (QUEUED) │ │
│ │ │ │
│ 3. 200 OK (otp_id, job_id) │ │ │
│<───────────────────────────────┤ │ │
│ │ 4. WS 'sms_gateway_dispatch' │ │
│ ├─────────────────────────────────>│ │
│ │ (Fallback: GET /pending) │ │
│ │ │ 5. SmsManager.sendTextMessage() │
│ │ ├────────────────────────────────>│
│ │ │ via Carrier SIM (GP/Robi/BL) │
│ │ │ │
│ │ 6. POST /device/status (SENT) │ │
│ │<─────────────────────────────────┤ │
│ │ │ │
│ 7. Webhook: 'sms.status_update'│ │ │
│<───────────────────────────────┤ │ │
│ │ │ │
│ 8. POST /verify-otp (phone,code) │ │
├───────────────────────────────>│ │ │
│ │ 9. Check single-use, TTL, │ │
│ │ & attempts (<=5) │ │
│ 10. 200 OK (verified: true) │ │ │
│<───────────────────────────────┤ │ │
│ │ │ │
Aggregators vs. SwapnoPay Cellular SIM
Why modern Bangladeshi businesses are shifting from predatory aggregator markups to in-house cellular SIM dispatch.
| Feature Metric | Traditional SMS Aggregators | SwapnoPay Cellular Gateway |
|---|---|---|
| Cost Per SMS | ৳0.35 – ৳0.65 per SMS | ৳0.00 (Flat Carrier Bundle: ~৳0.02) |
| Regulatory Bureaucracy | Requires trade license, BTRC approvals & weeks of verification | Zero approval waiting. Plug-and-play in 30 seconds. |
| Carrier Coverage | Restricted by gateway routing filters | All BD networks: Grameenphone, Robi, Banglalink, Teletalk |
| Delivery Latency | 3 – 15 seconds (queued via aggregators) | 1 – 3 seconds direct cellular transmission |
| Data Privacy | Customer phone numbers stored on third-party aggregator clouds | 100% self-hosted merchant privacy & direct SIM dispatch |
Authentication & Request Headers
Authenticate all external requests with your dedicated Merchant Gateway API Key.
| Header Name | Type | Description |
|---|---|---|
| x-api-key | string | Your unique gateway key starting with sp_gw_m_<merchant_id>_... |
| Authorization | string | Alternative bearer token format: Bearer <API_KEY> |
| Content-Type | string | Must be set to application/json. |
Core API Endpoints Reference
RESTful endpoints for OTP generation, verification, arbitrary notification broadcasts, and device telemetry.
/v1/sms-gateway/send-otp
Generates a cryptographically random numeric OTP, configures expiration TTL, saves it to the memory registry, and dispatches the SMS to the connected Android device via WebSockets.
| Field | Type | Default | Description |
|---|---|---|---|
| phone | string | Required | Recipient Bangladeshi phone number (e.g. 01712963652). |
| purpose | string | "Verification" | Action context (e.g. "Login", "Order #1029", "Withdrawal"). |
| expiryMinutes | number | 5 | OTP validity duration in minutes. |
| length | number | 6 | Digit length for the code (between 4 and 8). |
| template | string | Bengali Default | Custom template string. Replaces {code} or {otp}. |
{
"phone": "01712963652",
"purpose": "Customer Login Verification",
"expiryMinutes": 5,
"length": 6,
"template": "Your SwapnoPay verification code is: {code}. Valid for 5 minutes. Never share this."
}
{
"ok": true,
"otp_id": "otp_a4f891b2c3d4e5f6",
"job_id": "job_99812e4f01bc4a77",
"phone": "01712963652",
"purpose": "Customer Login Verification",
"expires_in_seconds": 300,
"message": "OTP queued for SIM dispatch"
}
/v1/sms-gateway/verify-otp
Validates the code entered by the user. Enforces strict single-use consumption and automatic invalidation after 5 unsuccessful attempts.
{
"phone": "01712963652",
"code": "582914",
"purpose": "Customer Login Verification"
}
{
"ok": true,
"verified": true,
"phone": "01712963652",
"purpose": "Customer Login Verification",
"message": "OTP verified successfully"
}
{
"ok": false,
"verified": false,
"error": "Incorrect OTP code",
"remaining_attempts": 4
}
/v1/sms-gateway/send
Broadcasts custom transactional notifications such as order shipping tracking, receipt confirmations, and account security alerts via your phone's SIM.
{
"phone": "01712963652",
"message": "Dear Tanvir, your order #ORD-9812 has been packed and handed to Pathao Courier. Tracking: https://track.example.com/9812",
"priority": "HIGH",
"webhook_url": "https://merchant.example.com/webhooks/sms-delivery"
}
{
"ok": true,
"job_id": "job_c18091ab42ef7a",
"phone": "01712963652",
"status": "QUEUED",
"message": "Message queued for SIM cellular dispatch"
}
/v1/sms-gateway/stats
Inspect real-time gateway throughput, check if your Android handset is online via live heartbeat telemetry, and monitor queue depth.
{
"ok": true,
"merchant_id": "00000000-0000-0000-0000-000000000001",
"device_online": true,
"stats": {
"queued": 0,
"sent": 1420,
"failed": 2,
"total_handled": 1422,
"active_otps": 3
}
}
phone_android Android Handset Protocol Endpoints
These endpoints are utilized by the SwapnoPay Android background service when operating in polling mode or reporting carrier transmission status.
/v1/sms-gateway/device/pending?merchant_id={id}
Fetches up to 20 queued SMS jobs and atomically sets their status to IN_PROGRESS.
/v1/sms-gateway/device/status
Reports transmission outcome (SENT or FAILED). Automatically invokes developer webhook_url if specified.
| Error Code | HTTP Status | Description & Suggested Action |
|---|---|---|
| Unauthorized | 401 | Missing or invalid x-api-key header. Check your merchant portal settings. |
| Valid phone number is required | 400 | Recipient phone number must be a valid 11-digit Bangladeshi mobile format. |
| No active OTP request found | 404 | No pending OTP code exists for this number, or it was already verified. |
| OTP has expired | 410 | The OTP TTL window elapsed. Prompt user to request a fresh OTP code. |
| Incorrect OTP code | 400 | Supplied code does not match. Displays remaining attempts (out of 5). |
| Too many incorrect attempts | 429 | Anti-bruteforce trigger. Maximum 5 attempts exceeded; OTP code immediately invalidated. |
Delivery Status Webhook Callbacks
Receive asynchronous HTTP delivery receipts directly to your server once the Android cellular SIM transmits the message.
When dispatching messages with a webhook_url specified, SwapnoPay immediately delivers an HTTP POST callback to your endpoint when the Android carrier network confirms dispatch:
{
"event": "sms.status_update",
"job_id": "job_c18091ab42ef7a",
"phone": "01712963652",
"status": "SENT",
"sent_at": 1773919283120,
"error": null
}
Webhook Handler Example (Node.js Express):
app.post('/webhooks/sms-delivery', (req, res) => {
const { event, job_id, phone, status, sent_at, error } = req.body;
if (event === 'sms.status_update') {
if (status === 'SENT') {
console.log(`[SMS Delivered] Job: ${job_id} to ${phone} at ${new Date(sent_at).toISOString()}`);
} else {
console.error(`[SMS Failed] Job: ${job_id} failed with error: ${error}`);
}
}
// Acknowledge receipt to avoid retries
res.status(200).json({ received: true });
});
Production SDK Code Examples
Copy-paste production integrations in cURL, Node.js, Python, PHP, and Kotlin.
# 1. Request OTP Dispatch
curl -X POST https://pay.swapnopay.top/v1/sms-gateway/send-otp \
-H "Content-Type: application/json" \
-H "x-api-key: sp_gw_m_000000000001_live_secret" \
-d '{
"phone": "01712963652",
"purpose": "Website Login",
"expiryMinutes": 5,
"length": 6
}'
# 2. Verify User OTP
curl -X POST https://pay.swapnopay.top/v1/sms-gateway/verify-otp \
-H "Content-Type: application/json" \
-H "x-api-key: sp_gw_m_000000000001_live_secret" \
-d '{
"phone": "01712963652",
"code": "582914"
}'
const axios = require('axios');
const SMS_API = axios.create({
baseURL: 'https://pay.swapnopay.top/v1/sms-gateway',
headers: {
'Content-Type': 'application/json',
'x-api-key': 'sp_gw_m_000000000001_live_secret'
}
});
// 1. Dispatch OTP
async function sendUserOtp(phone) {
const { data } = await SMS_API.post('/send-otp', {
phone,
purpose: 'Password Reset',
expiryMinutes: 5,
length: 6,
template: 'Your verification code is {code}. Never share it with anyone.'
});
return data;
}
// 2. Verify OTP
async function verifyUserOtp(phone, code) {
try {
const { data } = await SMS_API.post('/verify-otp', { phone, code });
return data.verified === true;
} catch (err) {
console.error('OTP Check failed:', err.response?.data?.error);
return false;
}
}
import requests
BASE_URL = "https://pay.swapnopay.top/v1/sms-gateway"
HEADERS = {
"Content-Type": "application/json",
"x-api-key": "sp_gw_m_000000000001_live_secret"
}
def send_otp(phone: str) -> dict:
resp = requests.post(f"{BASE_URL}/send-otp", headers=HEADERS, json={
"phone": phone,
"purpose": "Account Activation",
"expiryMinutes": 5,
"length": 6
})
return resp.json()
def verify_otp(phone: str, code: str) -> bool:
resp = requests.post(f"{BASE_URL}/verify-otp", headers=HEADERS, json={
"phone": phone,
"code": code
})
return resp.json().get("verified", False)
<?php
function sendSwapnoPayOtp($phone) {
$ch = curl_init('https://pay.swapnopay.top/v1/sms-gateway/send-otp');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json',
'x-api-key: sp_gw_m_000000000001_live_secret'
]);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
'phone' => $phone,
'purpose' => 'Checkout Verification',
'expiryMinutes' => 5,
'length' => 6
]));
$res = curl_exec($ch);
curl_close($ch);
return json_decode($res, true);
}
?>
val client = OkHttpClient()
val payload = JSONObject().apply {
put("phone", "01712963652")
put("purpose", "App Security Pin Reset")
put("expiryMinutes", 5)
put("length", 6)
}
val request = Request.Builder()
.url("https://pay.swapnopay.top/v1/sms-gateway/send-otp")
.addHeader("Content-Type", "application/json")
.addHeader("x-api-key", "sp_gw_m_000000000001_live_secret")
.post(payload.toString().toRequestBody("application/json".toMediaType()))
.build()
client.newCall(request).execute().use { response ->
val responseBody = response.body?.string()
println("Gateway Response: $responseBody")
}
Android Background Service & Dual-SIM Setup
Configuring your dedicated Android dispatch device for 24/7 autonomous transmission and battery optimization bypass.
battery_saver Battery Optimization Whitelist
To prevent Android OS (specifically Samsung OneUI, Xiaomi MIUI, and Android 14+ Doze Mode) from freezing background sockets, navigate to:
The app also requests REQUEST_IGNORE_BATTERY_OPTIMIZATIONS upon device pairing.
sim_card_download Dual-SIM Subscription Selection
The cellular gateway leverages Android's SubscriptionManager to dynamically route through SIM 1 or SIM 2 based on carrier bundle balance:
Set your preferred default SIM slot inside the SwapnoPay Android app settings.