DeveloperAPI Reference & Documentation

Developer API & Integration Guide

Welcome to the Message Panel REST API reference. Programmatically dispatch transactional SMS, trigger instant high-priority OTP verifications, inspect real-time delivery reports, and configure secure API keys with granular role-based permissions and IP allowlists.

Overview & Architecture

Message Panel provides a stateless, high-throughput REST API designed for enterprise SMS delivery and voice failover. All requests are authenticated via cryptographic API keys and protected by our distributed Anti-Fraud Shield.

Architecture
Stateless RESTful
JSON payloads for both request and response bodies.
High Availability
Multi-Gateway Routing
Sub-second dynamic carrier failover & DLT verification.
Security Standards
SHA-256 Storage
One-way hashed keys, CIDR IP filters & sliding rate limits.

Base URLs & Environments

EnvironmentBase URLKey TypeBilling Action
Production / Localhttps://msg.srotindia.com/msg-api/api/v1msg_live_...Real carrier dispatch & credit debit
Sandbox / Testinghttps://msg.srotindia.com/msg-api/api/v1msg_test_...Simulated delivery, ₹0 balance cost

Standard Response Envelope

Every HTTP response from our API adheres strictly to a predictable JSON envelope structure with a rootsuccess boolean flag.

200 OK / 201 Created Format
{
  "success": true,
  "data": {
    "messageId": "msg_98f418b7",
    "status": "queued",
    "recipient": "+919876543210",
    "creditsDeducted": 1,
    "remainingCredits": 7691
  },
  "message": "SMS dispatched successfully"
}
4xx / 5xx Error Format
{
  "success": false,
  "error": "Access denied: Insufficient permission for action 'reports'",
  "code": "FORBIDDEN_PERMISSION",
  "details": {
    "requiredScope": "reports",
    "keyPermission": "send"
  }
}

API Key Authentication

Authenticate requests by sending your secret API key in the HTTP request headers. Both the standard custom header x-api-key and the standard Authorization: Bearer format are fully supported.

Method 1 (Recommended)
x-api-key: msg_live_7ab...
Direct header inspected by API Gateway middleware.
Method 2 (Bearer Token)
Authorization: Bearer msg_live_7ab...
Standard OAuth / RFC-6750 compatible authorization header.

Key Formats & Secure Hashing

API Keys follow strict entropy standards and are prefixed for instant recognition in code reviews and secret scanners:

msg_live_...
Live Production Keys: Triggers immediate carrier submission via Tier-1 telecom routes. Debits standard wallet SMS credits.
msg_test_...
Sandbox Testing Keys: Generates simulated DLR callbacks, prevents real SMS sending, and costs ₹0.00 credits. Perfect for staging and automated CI/CD.
One-Way SHA-256 Storage: We never store plain-text API keys in our database. The moment you generate a key, our service computes sha256(rawKey) and stores only the hash and prefix. Copy your key immediately upon generation — it cannot be recovered afterwards.

IP Restriction & CIDR Allowlisting

When creating an API key, you can optionally configure an IP restriction. The API gateway validates every incoming HTTP request against the client IP extracted from x-forwarded-for or the TCP socket.

Single Static IP
203.0.113.195
Only requests originating from this exact IPv4 address are allowed.
CIDR Subnet Range
103.21.0.0/16
Allows any server residing within the entire /16 subnet block.

Requests from unauthorized IPs immediately receive HTTP 403 Forbidden with error code IP_RESTRICTED without debiting any credits.

Permission Scopes Matrix

Message Panel enforces granular Role-Based Access Control on every API key. Below is the complete matrix specifying exactly which endpoints, resources, and HTTP operations each permission level can access.

Endpoint & RouteAction / ResourceFull AccessSend OnlyReports OnlyRead Only
POST /sms/sendDispatch single or transactional SMS✔ Allowed✔ Allowed❌ 403 Blocked❌ 403 Blocked
POST /otp/sendGenerate & send 6-digit verification code✔ Allowed✔ Allowed❌ 403 Blocked❌ 403 Blocked
POST /otp/verifyValidate user OTP input token✔ Allowed✔ Allowed❌ 403 Blocked❌ 403 Blocked
GET /sms/logsList SMS logs & recipient phone numbers✔ Allowed❌ 403 Blocked✔ Allowed❌ 403 Blocked
GET /sms/logs/:idInspect carrier DLR and delivery timeline✔ Allowed❌ 403 Blocked✔ Allowed❌ 403 Blocked
GET /templatesFetch registered templates & DLT headers✔ Allowed❌ 403 Blocked❌ 403 Blocked✔ Allowed
GET /contactsRead contact groups and phone lists✔ Allowed❌ 403 Blocked❌ 403 Blocked✔ Allowed
GET /wallet/balanceView remaining OTP credits✔ Allowed❌ 403 Blocked❌ 403 Blocked❌ 403 Blocked
POST /developer/keysCreate, rotate, or delete API keys✔ Allowed❌ 403 Blocked❌ 403 Blocked❌ 403 Blocked
PERMISSION: full

Full Access Permission

Unrestricted master access to every resource across your organization. Best suited for backend microservice orchestrators or internal core engines that need to send messages, read logs, query billing, and rotate keys.

Allowed: SMS, OTP, Delivery Reports, Contacts, DLT Templates, Billing, API Key Management.
PERMISSION: send

Send Only Permission

Restricted strictly to outbound messaging. Keys with this scope can only invoke /sms/send and/otp/send. If a compromised microservice leaks this key, an attacker cannot read customer phone numbers, delivery logs, or wallet data.

Allowed: Outbound SMS dispatch and OTP requests only.
PERMISSION: reports

Reports Only Permission

Read-only access to transmission receipts, carrier DLR records, and analytics. Designed specifically for business intelligence (BI) pipelines, data warehouses (Snowflake, BigQuery), and customer support lookup tools.

Allowed: GET /sms/logs and GET /sms/logs/:id only. Sending is strictly blocked with HTTP 403.
PERMISSION: read

Read Only Permission

Enables inspecting static configuration, templates, sender IDs, and contact lists without ability to send messages or inspect real-time transmission logs.

Allowed: GET /templates, GET /contacts, GET /dlt/senderids.
POST/api/v1/sms/send
Requires Permission:fullorsend

Dispatch an immediate or scheduled transactional SMS to any global mobile number. Automatically validates E.164 phone number formatting and applies DLT template mapping.

Request Body (JSON)

ParameterTypeRequiredDescription
tostringYesDestination phone in E.164 format (e.g. +919876543210).
messagestringYesContent of message. 160 chars GSM-7 per credit (70 for Unicode).
senderIdstringOptional6-character registered header ID (e.g. MSGPAN).
templateIdstringOptionalRegistered TRAI DLT Template ID for Indian traffic.
curl -X POST https://msg.srotindia.com/msg-api/api/v1/sms/send \
  -H "Content-Type: application/json" \
  -H "x-api-key: msg_live_your_api_key_here" \
  -d '{
    "to": "+919876543210",
    "message": "Your verification code is 492104. Valid for 5 minutes.",
    "senderId": "MSGPAN"
  }'

200 OK Response

{
  "success": true,
  "data": {
    "messageId": "msg_98f418b7-6b45-4272-a169-e932b10a233b",
    "to": "+919876543210",
    "status": "queued",
    "creditsDeducted": 1,
    "remainingCredits": 7691,
    "carrierSubmittedAt": "2026-10-23T13:00:00.000Z"
  },
  "message": "SMS dispatched successfully"
}
POST/api/v1/otp/send
Permission: send or full

Dispatches an OTP via TRAI-approved Service Implicit telecom routes. Supports two core transmission architectures: AutoGen OTP (internal crypto engine or 2Factor delegated) and Custom OTP (customer supplies their own pre-generated authentication code).

Request Body (JSON)

ParameterTypeRequiredDescription
mobilestringYesDestination phone in E.164 format (e.g. +919876543210).
typestringOptional"autogen" (default) or "custom".
otpstringConditionalRequired when type: "custom". Customer-supplied code (4–8 digits).
strategystringOptional"internal" (default, resilient engine) or "twofactor".
otpLengthnumberOptionalLength of generated code (4 or 6, default 6).
expirySecondsnumberOptionalSession validity window (default 600 seconds / 10 minutes).

Example 1: AutoGen OTP (Internal Engine)

// POST /api/v1/otp/send
{
  "mobile": "+919876543210",
  "type": "autogen",
  "strategy": "internal",
  "otpLength": 6
}

// 201 Created Response:
{
  "success": true,
  "message": "OTP generated and dispatched successfully",
  "data": {
    "sessionId": "OTP_GEN_1792822088111_00AD91",
    "mobile": "+919876543210",
    "type": "autogen",
    "strategy": "internal",
    "expiresInSeconds": 600,
    "senderId": "MSGPAN"
  }
}

Example 2: Custom OTP (Customer Supplied Code)

// POST /api/v1/otp/send
{
  "mobile": "+919876543210",
  "type": "custom",
  "otp": "481920"
}

// 201 Created Response:
{
  "success": true,
  "message": "Custom OTP forwarded and dispatched via telecom gateway",
  "data": {
    "sessionId": "OTP_CUST_1792822088223_64C538",
    "mobile": "+919876543210",
    "type": "custom",
    "strategy": "internal",
    "expiresInSeconds": 600,
    "senderId": "MSGPAN"
  }
}

Queued sends (202) and the status endpoint

OTPs are handed to a worker that sends the SMS and retries on temporary gateway problems. Normally the worker finishes within a moment and you get the 201 above. If it is still working, you get 202 Accepted with status: "QUEUED". Your credit is reserved right away and refunded if the SMS could not be sent.

sessionId is always our own ID. Use it with /otp/verify, and to ask where the SMS is:

GET /api/v1/otp/sessions/{sessionId}/status        (needs your API key)

{ "success": true,
  "data": { "sessionId": "...", "status": "QUEUED" | "SENT" | "FAILED",
            "sentAt": "2026-10-27T10:00:01.000Z", "expiresAt": "...",
            "error": "only when FAILED" } }

Send an Idempotency-Key header to make retries safe: repeating a request with the same key returns the same session and never sends or charges twice. A code is valid for its full time starting from when the SMS is sent.

POST/api/v1/otp/verify
Public / API Key

Validates the user-entered OTP against the stored session ID. Supports sessions generated internally as well as upstream 2-Factor delegated sessions. Enforces maximum 5 attempts and automatic session expiration.

Request Payload

{
  "sessionId": "OTP_GEN_1792822088111_00AD91",
  "otp": "314213"
}

200 OK Response

{
  "success": true,
  "message": "OTP verified successfully",
  "data": {
    "verified": true,
    "sessionId": "OTP_GEN_1792822088111_00AD91",
    "phone": "+919876543210",
    "type": "AUTOGEN",
    "verifiedAt": "2026-10-24T06:08:08.204Z"
  }
}
GET/api/v1/otp/logs
Permission: reports or full

Retrieves real-time paginated OTP verification sessions for your organization. Filter by verification status (PENDING, VERIFIED, EXPIRED, FAILED) or search by recipient mobile number.

Query Parameters

Query ParamTypeDefaultDescription
pagenumber1Current page number.
limitnumber15Records per page (max 50).
statusstringALLFilter by status: VERIFIED, PENDING, etc.
GET/api/v1/sms/logs
Permission: reports or full

Query paginated transmission logs with status filter (queued,sent, delivered,failed).

Query Parameters

ParameterDefaultDescription
page1Page number for offset pagination.
limit20Records per page (Max: 100).
statusallFilter by status: delivered | failed | sent | queued.

200 OK Response

{
  "success": true,
  "data": [
    {
      "id": "clx_981a20",
      "recipient": "+919876543210",
      "senderId": "MSGPAN",
      "status": "delivered",
      "credits": 1,
      "submittedAt": "2026-10-23T12:50:00.000Z",
      "deliveredAt": "2026-10-23T12:50:04.000Z",
      "operatorCode": "AIRTEL-DELHI"
    }
  ],
  "pagination": { "total": 1420, "page": 1, "limit": 20, "totalPages": 71 }
}
GET/api/v1/sms/logs/:id
Requires Permission:reportsorfull

Retrieve real-time carrier delivery receipts (DLR), upstream telecom operator codes, dispatch timestamps, segment breakdown, and associated DLT template metadata for an individual transmission record by its ID.

Path Parameters

ParameterTypeRequiredDescription
idstringYesThe unique Message UUID or ID returned upon dispatch (e.g. d4e9b251-c031-482a-a5f1-389f46b14201).
curl -X GET https://msg.srotindia.com/msg-api/api/v1/sms/logs/d4e9b251-c031-482a-a5f1-389f46b14201 \
  -H "x-api-key: msg_live_your_api_key_here"

200 OK Response

{
  "success": true,
  "data": {
    "id": "d4e9b251-c031-482a-a5f1-389f46b14201",
    "orgId": "b5becc63-d569-4103-82ad-600842c7ba7e",
    "phone": "+919876543210",
    "senderId": "MSGPAN",
    "content": "Your login code is 492104. Valid for 5 minutes.",
    "charCount": 48,
    "encoding": "GSM-7",
    "segmentCount": 1,
    "creditsCharged": 1,
    "status": "DELIVERED",
    "deliveryCode": "DELIVRD",
    "deliveryCodeRaw": "000_SUCCESS",
    "deliveredAt": "2026-10-24T06:10:04.120Z",
    "isSandbox": false,
    "createdAt": "2026-10-24T06:10:01.000Z",
    "template": {
      "id": "tpl_891230",
      "templateName": "Login OTP Template",
      "dltTemplateId": "1407161234567890123",
      "category": "OTP"
    }
  },
  "timestamp": "2026-10-24T06:10:05.000Z"
}
GET/api/v1/wallet/balance
Requires Permission:fullorread

Query how many OTP credits your organization has left. One credit is used for each OTP that is actually sent.

curl -X GET https://msg.srotindia.com/msg-api/api/v1/wallet/balance \
  -H "x-api-key: msg_live_your_api_key_here"

200 OK Response

{
  "success": true,
  "data": {
    "otpCredits": 10,
    "plan": {
      "name": "Growth",
      "status": "ACTIVE",
      "includedOtpCredits": 1000,
      "endsAt": "2026-11-24T06:10:05.000Z",
      "inEffect": true
    }
  },
  "timestamp": "2026-10-24T06:10:05.000Z"
}
POST/api/v1/developer/keys
Admin / Owner Session or Full Access Key

Generate a new cryptographically secured API key with designated RBAC permission scopes (full, send, reports, read) and optional IPv4/CIDR network restriction. The raw secret is returned only once in the response payload.

Request Body (JSON)

ParameterTypeRequiredDescription
namestringYesHuman-readable label (e.g. "Production Microservice").
permissionstringOptionalScope: full | send | reports | read (Default: full).
environmentstringOptionalTarget environment: live | sandbox (Default: live).
ipRestrictstringOptionalStatic IPv4 address or CIDR range (e.g. 203.0.113.195 or 103.21.0.0/16).
curl -X POST https://msg.srotindia.com/msg-api/api/v1/developer/keys \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_SESSION_TOKEN" \
  -d '{
    "name": "Production Microservice",
    "permission": "send",
    "environment": "live",
    "ipRestrict": "203.0.113.195"
  }'

201 Created Response

{
  "success": true,
  "message": "API key generated successfully. Store the secret safely as it will not be displayed again.",
  "data": {
    "id": "key_e7829a4f",
    "name": "Production Microservice",
    "key": "msg_live_839f284a1e948301726a917240182c59",
    "keyPrefix": "msg_live_839f...",
    "permission": "send",
    "ipRestrict": "203.0.113.195",
    "environment": "live",
    "createdAt": "2026-10-24T06:12:00.000Z"
  },
  "timestamp": "2026-10-24T06:12:00.000Z"
}

HTTP Status Code Catalog

Our API uses conventional HTTP response codes to indicate the success or failure of an API request. Codes in the 2xx range indicate success, codes in the4xx range indicate an error that failed given the information provided, and codes in the 5xx range indicate an error with our servers.

CodeStatusMeaning & Trigger Reason
200OKEverything worked as expected.
201CreatedResource (API Key, Campaign, or SMS queue record) was created.
400Bad RequestMissing required parameters (e.g. missing to phone number).
401UnauthorizedNo valid API key provided or key has been revoked.
402Payment RequiredNo OTP credits left. Contact support to add more credits.
403ForbiddenKey permission mismatch (e.g. Send Only hitting Logs) or IP not in allowlist.
404Not FoundThe requested resource (message ID, contact ID) does not exist.
429Too Many RequestsExceeded 1,000 req/min rate limit or Anti-Fraud Shield cooldown triggered.
500Internal Server ErrorDownstream telecom gateway timeout or internal service disruption.

Application Error Codes Reference

When an API request fails, the code field in the error response contains a machine-readable string you can inspect in your catch handlers.

FORBIDDEN_PERMISSIONInsufficient Permission Scope
HTTP 403

Your API key does not have the required permission scope. For example, sending with a 'Reports Only' key, or reading delivery logs with a 'Send Only' key.

Resolution: Generate a new API key with 'Full Access' or the specific permission required.
IP_RESTRICTEDClient IP Outside Whitelist
HTTP 403

The HTTP request originated from an IP address not included in the API key's configured IP restriction CIDR block.

Resolution: Add your server's public outbound IP to the API key's IP restriction list in the dashboard.
INVALID_API_KEYMalformed or Revoked Key
HTTP 401

The provided x-api-key could not be found or has been revoked.

Resolution: Check for trailing spaces or verify key active status in /dashboard/apikeys.
INSUFFICIENT_CREDITSOTP Credits Exhausted
HTTP 402

Your organization has no OTP credits left, so the OTP was not sent.

Resolution: Ask the platform admin to add OTP credits.
FRAUD_SHIELD_COOLDOWNPer-Phone Cooldown Active
HTTP 429

An OTP or SMS was recently dispatched to this phone number within the 60-second cooldown window.

Resolution: Wait 60 seconds before re-attempting OTP delivery to the same phone number.
HOURLY_ATTEMPT_LIMITMaximum Hourly Attempts Exceeded
HTTP 429

More than 5 OTP requests were dispatched to this phone number in the past 60 minutes.

Resolution: Contact support or wait for the sliding 1-hour window to expire.

Anti-Fraud Shield Rules

To protect your OTP credits against SMS pumping fraud, brute force OTP attacks, and bot swarms, all messaging endpoints are guarded by Redis-backed real-time sliding window algorithms:

60s Cooldown

Maximum 1 OTP request per phone number every 60 seconds. Prevents user double-clicking and SMS flooding.

5 Attempts / Hour

Strict cap of 5 OTP dispatches per phone number per sliding 60-minute window. Thwarts persistent abusers.

20 Req/Min IP Cap

Global rate limit of 20 requests per minute per IP address to block distributed botnet credential stuffing.

Magic Sandbox Test Phone

Need to run automated CI/CD unit tests or App Store review submissions without consuming credits or triggering the 60-second fraud cooldown? Use our built-in magic test number:

Magic Phone Number
+919999999999
Magic Verification OTP
123456

When dispatched to +919999999999, our engine bypasses carrier dispatch, skips wallet deduction, bypasses cooldown limits, and immediately accepts 123456.

Webhooks & Real-Time Delivery Receipts

Configure Webhooks under /dashboard/webhooks to receive HTTP POST notifications whenever a message status updates.

Supported Event Types

sms.delivered Carrier handset delivery confirmation
sms.failed DND reject or invalid mobile subscriber
otp.verified Successful OTP token match event
carrier.failover Voice call failover triggered

HMAC-SHA256 Signature Verification

Every webhook request includes an x-signature header computed as:

const crypto = require("crypto");

function verifyWebhook(payload, signature, secret) {
  const hmac = crypto.createHmac("sha256", secret).update(JSON.stringify(payload)).digest("hex");
  return crypto.timingSafeEqual(Buffer.from(hmac), Buffer.from(signature));
}

OTP Widget: Install on Your Website

The widget is a ready-made popup. Your visitor enters a mobile number, receives a code, and enters it. You do not build any OTP screens and your API key never goes into the page. Create a widget under /dashboard/widget, list the websites allowed to use it, then paste:

<script src="https://YOUR_API_DOMAIN/widget/v1/widget.js"
        data-widget-key="wgt_xxxxxxxxxxxxxxxxxxxxxxxx"
        data-trigger="#verify-phone"
        data-on-success="onPhoneVerified"></script>

<button id="verify-phone">Verify phone number</button>

<script>
  function onPhoneVerified(result) {
    // result.token  -> send this to YOUR server (see next section)
    // result.mobile -> masked number, e.g. +91******10
  }
</script>

Open it from your own code instead

MessagePanelOTP.open({
  mobile: "9876543210",              // optional, pre-fills the number
  onSuccess: (r) => { /* r.token, r.mobile */ },
  onError:   (e) => { /* widget could not start */ },
  onClose:   (c) => { /* c.verified is true or false */ },
});
  • The widget only works on the websites you list (exact origin, such as https://shop.example.com). Other sites are refused.
  • Test mode sends no SMS and uses no credits; the code is shown in the popup. Turn it off to go live.
  • Each live send uses 1 OTP credit. Every widget has a daily send cap, and the usual per-number and per-IP limits apply.
  • Indian mobile numbers (+91) only.

OTP Widget: Verify on Your Server

A browser can be faked, so the success callback alone proves nothing. Send result.token to your server and confirm it with your API key (a key with send or full permission). The token works once and expires after 10 minutes.

curl -X POST https://YOUR_API_DOMAIN/api/v1/widget/token/verify \
  -H "x-api-key: msg_live_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{"token":"TOKEN_FROM_THE_BROWSER"}'

{
  "success": true,
  "data": {
    "verified": true,
    "mobile": "+919876543210",
    "widgetId": "…",
    "sessionId": "…",
    "verifiedAt": "2026-10-27T10:00:00.000Z"
  }
}

A reused, expired or tampered token returns 400. Only mark the phone as verified when you get verified: true.

Ready to integrate?

Generate your first API key and start sending live messages in less than 3 minutes.

Go to API Keys