ISMS Plus SMS API

Programmatic SMS messaging — send single, bulk, OTP, and dynamic messages.

Base URL
https://smsplus.sslwireless.com/api/v3

Single SMS

Send a single SMS message to one recipient

Secure OTP

Send one-time-password SMS messages

Bulk SMS

Send same message to multiple recipients

Dynamic SMS

Send unique messages to different recipients

Base Configuration

Content Type
application/json
Response Type
JSON
Authentication
api_token
Max MSISDN/Request
100

Authentication

Every request requires an api_token and sid (Sender ID).

api_token — Your unique API token (e.g., XXXX-XXd2bbXX-XXfX-XXbf-XXXXX-XXXXXcXXXXX)
sid — Your registered Sender ID (e.g., XXXXXXXXXX)
Request IP — Must be whitelisted in ISMS Plus portal

Response Format

All SMS endpoints return a consistent JSON structure. Fields vary slightly by endpoint but follow this common shape.

Top-level Fields

Parameter Type Description
status string Overall result — SUCCESS or FAILED
status_code integer Numeric status code — see API Status Codes
error_message string Human-readable error detail if failed; empty string on success
smsinfo array Array of SMS detail objects, one per recipient (see below)

smsinfo Object Fields

Parameter Type Description
smsinfo[].sms_status string Per-recipient status: SUCCESS, INVALID, DUPLICATE, or BLOCKED
smsinfo[].status_message string Human-readable status message for this recipient
smsinfo[].msisdn string The recipient phone number (with country code prefix)
smsinfo[].sms_type string EN for English & BN for Unicode / Bangla
smsinfo[].csms_id string Your provided client reference ID
smsinfo[].reference_id string Server-generated unique reference ID (use for status checks)
GET|POST

Send SMS

Send a single SMS message to one recipient.

https://smsplus.sslwireless.com/api/v3/send-sms

Parameters

Name Required Type Length Description
api_token Required Alphanumeric 50 Authentication token provided by SSL
sid Required Alphanumeric 20 Sender ID
msisdn Required Numeric 16 Recipient mobile phone number
sms Required Alphanumeric 1000 SMS message body
csms_id Required Alphanumeric 20 Unique client reference ID for this SMS

Sample Request

Request Body
{
  "api_token": "XXXX-XXd2bbXX-XXfX-XXbf-XXXXX-XXXXXcXXXXX",
  "sid": "XXXXXXXXXX",
  "msisdn": "88019XXXXXXXX",
  "sms": "Message Body",
  "csms_id": "4473433434pZ684333392"
}

Success Response

Success
{
  "status": "SUCCESS",
  "status_code": 200,
  "error_message": "",
  "smsinfo": [
    {
      "sms_status": "SUCCESS",
      "status_message": "Success",
      "msisdn": "88019XXXXXXXX",
      "sms_type": "EN",
      "sms_body": "Your sms body",
      "csms_id": "4473433434pZ684333392",
      "reference_id": "5da2f0b5ba3a2248110"
    }
  ]
}

Failure Response

Failure
{
  "status": "FAILED",
  "status_code": 4025,
  "error_message": "Invalid MSISDN",
  "smsinfo": [
    {
      "sms_status": "INVALID",
      "status_message": "Invalid MSISDN",
      "msisdn": "88019XXXXXXXX",
      "sms_type": "EN",
      "csms_id": "4473433434pZ684333392",
      "reference_id": "5da2f0b5ba3a2248110"
    }
  ]
}
POST

Secure OTP SMS with Signature

SMS body must be AES-256-CBC encrypted — plus an additional X-Signature request header for payload integrity verification.

https://smsplus.sslwireless.com/api/v3/secure/otp-sms
Two-layer security: Both operations use the same Secret Key shared via ISMS Plus portal. The sms field is AES-256-CBC encrypted with SHA256(secret_key), and X-Signature header is an HMAC-SHA256 of payload signed with secret_key. The server rejects requests where either check fails with 4035 SIGNATURE_MISMATCH.

Request Headers

Header Type Required Description
Content-Type string Required application/json
X-Signature string Required HMAC-SHA256 signature of payload (hex string) — see generation steps below

Request Parameters

Name Required Type Length Description
api_token Required Alphanumeric 50 Authentication token provided by SSL
sid Required Alphanumeric 20 Sender ID
msisdn Required Numeric 16 Recipient mobile phone number
sms Required Encrypted 1000 SMS body encrypted using the user's secret key
csms_id Required Alphanumeric 20 Unique client reference ID for this SMS

Signature Generation

Build X-Signature header value using these exact steps:
  1. Obtain your Secret Key from the ISMS Plus portal.
  2. Encrypt SMS Text: Use AES-256-CBC with PKCS7 padding.
    • Key: Take the first 32 characters of the SHA256 hex hash of your Secret Key.
    • Format: Base64 encode the concatenation of the [16-byte raw IV] + [Base64 encoded ciphertext].
  3. Generate Canonical String: Create a URL‑encoded query string using this exact pattern csms_id=123&msisdn=456&sid=789&sms=encrypted_string.
  4. Compute HMAC: Calculate HMAC-SHA256 using the raw Secret Key as the key and the query string as the message.
  5. Send the resulting lowercase hex digest as the X-Signature header.

Sample Request

Request Body
{
  "api_token": "XXXX-XXd2bbXX-XXfX-XXbf-XXXXX-XXXXXcXXXXX",
  "sid": "XXXXXXXXXX",
  "msisdn": "88019XXXXXXXX",
  "sms": "<AES-256-CBC-ENCRYPTED-BASE64-STRING>",
  "csms_id": "4473433434pZ684333392"
}

Success Response

Success
{
  "status": "SUCCESS",
  "status_code": 200,
  "error_message": "",
  "smsinfo": [
    {
      "sms_status": "SUCCESS",
      "status_message": "Success",
      "msisdn": "8801XXXXXXXXX",
      "sms_type": "EN",
      "csms_id": "4473433434pZ684333392",
      "reference_id": "5d9d7ca5dac5e067314"
    }
  ]
}

Failure Response

Signature Mismatch
{
  "status": "FAILED",
  "error_message": "Client signature mismatch",
  "status_code": 4035,
  "smsinfo": []
}
POST

Bulk SMS

Send a single SMS message body to multiple recipients in one request. Maximum 100 MSISDN per request.

https://smsplus.sslwireless.com/api/v3/send-sms/bulk
📦 MSISDN limit per request: 100. Exceeding this limit will result in error code 4030.

Parameters

Name Required Type Length Description
api_token Required Alphanumeric 50 Authentication token provided by SSL
sid Required Alphanumeric 20 Sender ID
msisdn Required Array<Numeric> 16 each Array of recipient mobile phone numbers
sms Required Alphanumeric 1000 SMS message body
batch_csms_id Required Alphanumeric 20 Unique client reference ID for this batch

Sample Request

Request Body
{
  "api_token": "XXXX-XXd2bbXX-XXfX-XXbf-XXXXX-XXXXXcXXXXX",
  "sid": "XXXXXXXXXX",
  "msisdn": [
    "88019XXXXXXXX",
    "88017XXXXXXXX",
    "88018XXXXXXXX"
  ],
  "sms": "Message Body",
  "batch_csms_id": "4437343343P3Z684333392"
}

Success Response

Success
{
  "status": "SUCCESS",
  "status_code": 200,
  "error_message": "",
  "smsinfo": [
    {
      "sms_status": "SUCCESS",
      "status_message": "Success",
      "msisdn": "88019XXXXXXXX",
      "sms_type": "EN",
      "csms_id": "4473433434pZ684333392",
      "reference_id": "5da2f0b5ba3a2248110"
    },
    {
      "sms_status": "SUCCESS",
      "status_message": "Success",
      "msisdn": "88017XXXXXXXX",
      "sms_type": "EN",
      "csms_id": "4473433434pZ684333393",
      "reference_id": "5da2f0b5ba3a2248111"
    }
  ]
}

Failure Response

Failure
{
  "status": "FAILED",
  "status_code": 4028,
  "error_message": "Invalid message data",
  "smsinfo": [
    {
      "sms_status": "DUPLICATE",
      "status_message": "Duplicated CSMS ID",
      "msisdn": "88019XXXXXXXX",
      "sms_type": "EN",
      "csms_id": "4473433434pZ684333392",
      "reference_id": "5da2f0b5ba3a2248110"
    }
  ]
}
POST

Dynamic SMS

Send unique SMS messages to different recipients in a single request. Each recipient gets a personalized message.

https://smsplus.sslwireless.com/api/v3/send-sms/dynamic
📨 SMS limit per request: 100. Each object in the sms array represents a unique message to a unique recipient.

Parameters

Name Required Type Length Description
api_token Required Alphanumeric 50 Authentication token provided by SSL
sid Required Alphanumeric 20 Sender ID
sms Required Array<Object> Array of SMS objects with msisdn, text, csms_id
sms[].msisdn Required Numeric 16 Recipient mobile phone number
sms[].text Required Alphanumeric 1000 The SMS message body for this recipient
sms[].csms_id Required Alphanumeric 20 Unique client reference ID per SMS

Sample Request

Request Body
{
  "api_token": "XXXX-XXd2bbXX-XXfX-XXbf-XXXXX-XXXXXcXXXXX",
  "sid": "XXXXXXXXXX",
  "sms": [
    {
      "msisdn": "88019XXXXXXXX",
      "text": "Message Body 1",
      "csms_id": "234444343222"
    },
    {
      "msisdn": "88017XXXXXXXX",
      "text": "Message Body 2",
      "csms_id": "234444343223"
    }
  ]
}

Success Response

Success
{
  "status": "SUCCESS",
  "status_code": 200,
  "error_message": "",
  "smsinfo": [
    {
      "sms_status": "SUCCESS",
      "status_message": "Success",
      "msisdn": "88019XXXXXXXX",
      "sms_type": "EN",
      "csms_id": "234444343222",
      "reference_id": "5da2f0b5ba3a2248110"
    },
    {
      "sms_status": "SUCCESS",
      "status_message": "Success",
      "msisdn": "88017XXXXXXXX",
      "sms_type": "EN",
      "csms_id": "234444343223",
      "reference_id": "5da2f0b5ba3a2248111"
    }
  ]
}

Failure Response

Failure
{
  "status": "FAILED",
  "status_code": 4028,
  "error_message": "Invalid message data",
  "smsinfo": [
    {
      "sms_status": "DUPLICATE",
      "status_message": "Duplicated CSMS ID",
      "msisdn": "88019XXXXXXXX",
      "sms_type": "EN",
      "csms_id": "4473433434pZ684333392",
      "reference_id": "5da2f0b5ba3a2248110"
    }
  ]
}

API Status Codes

All API responses include a numeric status code indicating the result of your request.

Code Status Description
200 SUCCESS Request completed successfully
4001 Unauthorized Authentication failed
4002 SID Not Permitted Stakeholder not permitted to send SMS
4003 IP Blacklisted IP is not whitelisted
4004 Invalid Request Format JSON format is invalid or content type is not JSON
4005 End Point Not Found The requested endpoint does not exist
4020 Invalid CSMS ID Only for bulk and single SMS
4022 Required Parameter Missing A required field is missing (sid, msisdn, etc.)
4023 Duplicate CMS ID Only for bulk and single SMS
4024 Duplicate MSISDN Only for single SMS
4025 Invalid MSISDN The MSISDN provided is invalid
4026 Blocked MSISDN The MSISDN is blocked
4027 Message Length Exceeded Only for single SMS
4028 Invalid Message Data Invalid MSISDN, SMS Body, SID, CSMSID, or missing mandatory field
4029 Too Many Requests Rate limit exceeded
4030 Limit Exceed Max MSISDN list exceeded for one request
4031 TPS Exceeded Transactions per second limit exceeded
4032 Invalid SMS Invalid SMS body
4033 Too Many OTP Requests Too many OTPs sent to a single recipient within a time period
4034 Unable to Decrypt SMS SMS body not encrypted, invalid secret key, or wrong encryption method
4035 Client Signature Mismatch Signature header sent but process not followed correctly
5000 Internal Error Server internal error

SMS Status

Each SMS within a response carries its own delivery status.

Status Message Description
SUCCESS Success SMS delivered successfully
INVALID Invalid MSISDN Message length exceeded or invalid phone number
DUPLICATE Duplicate CMS ID Duplicate MSISDN detected
BLOCKED Blocked MSISDN Too many OTP requests or MSISDN blocked

Sample Code

Here are some examples of how to integrate the SMS API in different programming languages.

PHP - Single SMS
<?php
$url = "https://smsplus.sslwireless.com/api/v3/send-sms";
$data = [
    "api_token" => "your_api_token",
    "sid" => "XXXXXXXXXX",
    "msisdn" => "88019XXXXXXXX",
    "sms" => "Message Body",
    "csms_id" => "4473433434pZ684333392"
];

$ch = curl_init($url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'Accept: application/json'
]);

$response = curl_exec($ch);
curl_close($ch);
echo $response;
?>
Python (Requests) - Single SMS
import requests

url = "https://smsplus.sslwireless.com/api/v3/send-sms"
headers = {"Content-Type": "application/json", "Accept": "application/json"}
payload = {
    "api_token": "your_api_token",
    "sid": "XXXXXXXXXX",
    "msisdn": "88019XXXXXXXX",
    "sms": "Message Body",
    "csms_id": "4473433434pZ684333392"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
Node.js (Fetch) - Single SMS
const payload = {
  api_token: "your_api_token",
  sid: "XXXXXXXXXX",
  msisdn: "88019XXXXXXXX",
  sms: "Message Body",
  csms_id: "4473433434pZ684333392"
};
fetch("https://smsplus.sslwireless.com/api/v3/send-sms", {
  method: "POST",
  headers: {"Content-Type":"application/json", "Accept":"application/json"},
  body: JSON.stringify(payload)
}).then(r => r.json()).then(console.log);
Bash (cURL) - Single SMS
curl -X POST https://smsplus.sslwireless.com/api/v3/send-sms \
  -H 'Content-Type: application/json' \
  -H 'Accept: application/json' \
  -d '{
  "api_token": "your_api_token",
  "sid": "XXXXXXXXXX",
  "msisdn": "88019XXXXXXXX",
  "sms": "Message Body",
  "csms_id": "4473433434pZ684333392"
}'
Go (net/http)
package main

import (
	"bytes"
	"fmt"
	"net/http"
)

func main() {
	url := "https://smsplus.sslwireless.com/api/v3/send-sms"
	payload := []byte(`{
  "api_token": "your_api_token",
  "sid": "XXXXXXXXXX",
  "msisdn": "88019XXXXXXXX",
  "sms": "Message Body",
  "csms_id": "4473433434pZ684333392"
}`)

	req, _ := http.NewRequest("POST", url, bytes.NewBuffer(payload))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Accept", "application/json")

	client := &http.Client{}
	resp, _ := client.Do(req)
	defer resp.Body.Close()

	fmt.Println("Status:", resp.Status)
}
C# (.NET HttpClient)
using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

class Program {
    static async Task Main() {
        var client = new HttpClient();
        var url = "https://smsplus.sslwireless.com/api/v3/send-sms";

        var json = @"{
  "api_token": "your_api_token",
  "sid": "XXXXXXXXXX",
  "msisdn": "88019XXXXXXXX",
  "sms": "Message Body",
  "csms_id": "4473433434pZ684333392"
}";

        var content = new StringContent(json, Encoding.UTF8, "application/json");
        client.DefaultRequestHeaders.Add("Accept", "application/json");

        var response = await client.PostAsync(url, content);
        Console.WriteLine(await response.Content.ReadAsStringAsync());
    }
}
Java (HttpClient)
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        String url = "https://smsplus.sslwireless.com/api/v3/send-sms";
        String json = "{\n"
                + "  \"api_token\": \"your_api_token\",\n"
                + "  \"sid\": \"XXXXXXXXXX\",\n"
                + "  \"msisdn\": \"88019XXXXXXXX\",\n"
                + "  \"sms\": \"Message Body\",\n"
                + "  \"csms_id\": \"4473433434pZ684333392\"\n"
                + "}";

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/json")
                .header("Accept", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}
PHP - Secure OTP + Signature
<?php
function encryptSms(string $plainText, string $secretKey): string {
    $method = 'AES-256-CBC';
    $key    = hash('sha256', $secretKey);  // Derive key from portal Secret Key
    $ivLen  = openssl_cipher_iv_length($method);
    $iv     = openssl_random_pseudo_bytes($ivLen);
    $cipher = openssl_encrypt($plainText, $method, $key, 0, $iv);
    return base64_encode($iv . $cipher);
}

$apiToken  = 'YOUR_API_TOKEN';
$secretKey = 'YOUR_SECRET_KEY';
$sid       = 'YOUR_SID';
$msisdn    = '01XXXXXXXXX';
$csmsId    = 'SSIG-ID-001';

// Step 1: Encrypt the OTP message using the portal Secret Key
$encryptedSms = encryptSms('Your OTP is 123456', $secretKey);

// Step 2: Build signature payload
$hashPayload = [
    'sid'     => $sid,
    'msisdn'  => $msisdn,
    'sms'     => $encryptedSms,
    'csms_id' => $csmsId,
];

// Step 3: Always sort the payload alphabetically by key
// This ensures the receiver can recreate the exact same string
ksort($hashPayload);

// Step 4: Build the query string (e.g., sid=123&msisdn=456...)
$queryString = http_build_query($hashPayload);

// Step 5: Sign the query string
$signature = hash_hmac('sha256', $queryString, $secretKey);

// Step 3: Send request
$data = [
    'api_token' => $apiToken,
    'sid'       => $sid,
    'msisdn'    => $msisdn,
    'sms'       => $encryptedSms,
    'csms_id'   => $csmsId,
];
$ch = curl_init('https://smsplus.sslwireless.com/api/v3/secure/otp-sms');
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
    'Content-Type: application/json',
    'X-Signature: ' . $signature,
]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
echo curl_exec($ch);
curl_close($ch);
Python (Requests) - Secure OTP + Signature
import requests
import hashlib
import base64
import hmac
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from Crypto.Random import get_random_bytes

def encrypt_sms(plain_text: str, secret_key: str) -> str:
    # 1. A 64-char hex string
    key_hash_hex = hashlib.sha256(secret_key.encode()).hexdigest()

    # 2. OpenSSL AES-256 uses the first 32 characters of that hex string
    key = key_hash_hex[:32].encode()

    # 3. Generate 16-byte random IV
    iv = get_random_bytes(16)

    # 4. Create cipher and pad data (PKCS7)
    cipher = AES.new(key, AES.MODE_CBC, iv)
    padded_data = pad(plain_text.encode('utf-8'), AES.block_size)

    # 5. Encrypt to raw bytes
    raw_ciphertext = cipher.encrypt(padded_data)

    # 6. openssl_encrypt with flag 0 returns a Base64 string
    base64_ciphertext = base64.b64encode(raw_ciphertext).decode('utf-8')

    # 7. base64_encode($iv . $encrypted)
    # Note: $iv is binary, $encrypted is the base64 string from step 6
    combined = iv + base64_ciphertext.encode('utf-8')
    return base64.b64encode(combined).decode('utf-8')


api_token = 'YOUR_API_TOKEN'
secret_key = 'YOUR_SECRET_KEY'
sid = 'YOUR_SID'
msisdn = '01XXXXXXXXX'
csms_id = 'SSIG-ID-001'

# Step 1: Encrypt the OTP message
encrypted_sms = encrypt_sms('Your OTP is 123456', secret_key)
print("Encrypted SMS: ", encrypted_sms)

# Step 2: Build signature payload
hash_payload = {
    'sid': sid,
    'msisdn': msisdn,
    'sms': encrypted_sms,
    'csms_id': csms_id
}

# Step 3: Always sort the payload alphabetically by key
# This ensures the receiver can recreate the exact same string
hash_payload = dict(sorted(hash_payload.items()))

# Step 4: Build the query string (e.g., sid=123&msisdn=456...)
from urllib.parse import urlencode

query_string = urlencode(hash_payload)

# Step 5: Sign the query string
signature = hmac.new(secret_key.encode(), query_string.encode(), hashlib.sha256).hexdigest()

# Step 3: Send request
data = {
    'api_token': api_token,
    'sid': sid,
    'msisdn': msisdn,
    'sms': encrypted_sms,
    'csms_id': csms_id
}

headers = {
    'Content-Type': 'application/json',
    'X-Signature': signature
}

response = requests.post(
    'https://smsplus.sslwireless.com/api/v3/secure/otp-sms',
    json=data,
    headers=headers
)
print(response.json())
Node.js (Fetch) - Secure OTP + Signature
const crypto = require('crypto');
// fetch is available globally in Node 18+


// Encrypt SMS using AES-256-CBC
function encryptSms(plainText, secretKey) {
  // OpenSSL uses first 32 bytes (chars) of that hex string as the AES-256 key
  const keyHex = crypto.createHash('sha256').update(secretKey).digest('hex');
  const key = Buffer.from(keyHex.slice(0, 32)); // first 32 chars → 32 bytes


  const iv = crypto.randomBytes(16);
  const cipher = crypto.createCipheriv('aes-256-cbc', key, iv);


  //Openssl_encrypt with flag=0 returns base64-encoded ciphertext
  let encryptedRaw = cipher.update(plainText, 'utf8');
  encryptedRaw = Buffer.concat([encryptedRaw, cipher.final()]);
  const encryptedBase64 = encryptedRaw.toString('base64'); // mimic openssl_encrypt flag=0


  // base64_encode($iv . $encrypted) → raw IV bytes + base64 string, then base64 encode
  return Buffer.concat([iv, Buffer.from(encryptedBase64)]).toString('base64');
}


// Generate signature with new logic
function generateSignature(csmsId, msisdn, sid, sms, secretKey) {
  // Step 1: Build payload map
  const payload = { csms_id: csmsId, msisdn, sid, sms };


  // Step 2: Sort keys alphabetically
  const sortedKeys = Object.keys(payload).sort();


  // Step 3: Build URL-encoded query string
  const queryString = sortedKeys
    .map(key => `${key}=${encodeURIComponent(payload[key])}`)
    .join('&');


  // Step 4: HMAC-SHA256 with raw secret key
  return crypto.createHmac('sha256', secretKey)
    .update(queryString)
    .digest('hex'); // lowercase hex
}


(async () => {
    const apiToken = 'YOUR_API_TOKEN';
    const secretKey = 'YOUR_SECRET_KEY';
    const sid = 'YOUR_SID';
    const msisdn = '01XXXXXXXXX';
    const csmsId = 'SSIG-ID-001';


  // Step 1: Encrypt the OTP message
  const encryptedSms = encryptSms('Your OTP is 123456', secretKey);


  // Step 2: Generate signature
  const signature = generateSignature(csmsId, msisdn, sid, encryptedSms, secretKey);


  // Step 3: Build request payload
  const payload = {
    api_token: apiToken,
    sid,
    msisdn,
    sms: encryptedSms,
    csms_id: csmsId
  };


  // Step 4: Send request
  const response = await fetch('https://smsplus.sslwireless.com/api/v3/secure/otp-sms', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'X-Signature': signature
    },
    body: JSON.stringify(payload)
  });


  const data = await response.json();
  console.log(data);
})();
Go (net/http) - Secure OTP + Signature
package main

import (
    "bytes"
    "crypto/aes"
    "crypto/cipher"
    "crypto/hmac"
    "crypto/rand"
    "crypto/sha256"
    "encoding/base64"
    "encoding/hex"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
    "net/url"
)

func sendSecureOtp() {
    apiToken := "***YOUR_API_TOKEN***"
    secretKey := "YOUR_SECRET_KEY"
    sid := "***YOUR_SID***"
    msisdn := "01XXXXXXXXX"
    csmsId := "SSIG-ID-XXX"

    encryptedSms, err := encryptSms("Your test pin is 1234", secretKey)

    if err != nil {
       fmt.Println("Encryption error:", err)
       return
    }
    signature, err := makeSignature(csmsId, msisdn, sid, encryptedSms, secretKey)
    println("Signature: ", signature)
    if err != nil {
       fmt.Println("Error to make signature error:", err)
       return
    }
    // Step 3: Send request
    payload := map[string]interface{}{
       "api_token": apiToken,
       "sid":       sid,
       "msisdn":    msisdn,
       "sms":       encryptedSms,
       "csms_id":   csmsId,
    }

    jsonData, _ := json.Marshal(payload)
    req, _ := http.NewRequest("POST",
       "https://smsplus.sslwireless.com/api/v3/secure/otp-sms",
       bytes.NewBuffer(jsonData))
    req.Header.Set("Content-Type", "application/json")
    req.Header.Set("X-Signature", signature)

    client := &http.Client{}
    resp, err := client.Do(req)
    if err != nil {
       fmt.Println("Request error:", err)
       return
    }
    defer resp.Body.Close()

    body, _ := io.ReadAll(resp.Body)
    fmt.Println(string(body))
}

func encryptSms(plainText, secretKey string) (string, error) {
    // 1.hash('sha256', $key) returns a 64-char hex string
    hash := sha256.Sum256([]byte(secretKey))
    hashHex := hex.EncodeToString(hash[:])

    // OpenSSL AES-256 uses the first 32 bytes of that string
    key := []byte(hashHex)[:32]

    block, err := aes.NewCipher(key)
    if err != nil {
       return "", err
    }

    // 2. Generate 16-byte IV
    iv := make([]byte, aes.BlockSize)
    if _, err := io.ReadFull(rand.Reader, iv); err != nil {
       return "", err
    }

    // 3. PKCS7 Padding
    paddedText := pkcs7Pad([]byte(plainText), aes.BlockSize)

    // 4. Encrypt to raw bytes
    ciphertext := make([]byte, len(paddedText))
    mode := cipher.NewCBCEncrypter(block, iv)
    mode.CryptBlocks(ciphertext, paddedText)

    //5. We must encode the ciphertext bytes to Base64 first
    base64Ciphertext := base64.StdEncoding.EncodeToString(ciphertext)

    // 6. Concatenate Binary IV + Base64 Ciphertext String
    // Then Base64 encode the whole thing
    combined := append(iv, []byte(base64Ciphertext)...)
    return base64.StdEncoding.EncodeToString(combined), nil
}

func pkcs7Pad(data []byte, blockSize int) []byte {
    padding := blockSize - (len(data) % blockSize)
    padtext := bytes.Repeat([]byte{byte(padding)}, padding)
    return append(data, padtext...)
}

func makeSignature(CsmsId string, msisdn string, sid string, encryptedSms string, userSecreteKey string) (string, error) {
    values := url.Values{}
    values.Set("csms_id", CsmsId)
    values.Set("msisdn", msisdn)
    values.Set("sid", sid)
    values.Set("sms", encryptedSms)
    queryString := values.Encode()

    h := hmac.New(sha256.New, []byte(userSecreteKey))
    h.Write([]byte(queryString))
    return hex.EncodeToString(h.Sum(nil)), nil
}
C# (.NET HttpClient) - Secure OTP + Signature
using System;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Linq;

class Program
{
    // Encrypt SMS using AES-256-CBC
   public static string EncryptSms(string plainText, string secretKey)
{
    //hash('sha256', $key) returns a 64-char HEX string
    using var sha256 = SHA256.Create();
    byte[] hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(secretKey));
    string hexKey = BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
    // openssl uses first 32 bytes of the hex string as the AES-256 key
    byte[] key = Encoding.UTF8.GetBytes(hexKey).Take(32).ToArray();
    // Generate random IV
    byte[] iv = new byte[16];
    using var rng = RandomNumberGenerator.Create();
    rng.GetBytes(iv);
    using var aes = Aes.Create();
    aes.Key = key;
    aes.IV = iv;
    aes.Mode = CipherMode.CBC;
    aes.Padding = PaddingMode.PKCS7;
    using var encryptor = aes.CreateEncryptor();
    byte[] plainBytes = Encoding.UTF8.GetBytes(plainText);
    byte[] encryptedRaw = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);
    // flag=0 means openssl_encrypt returns base64-encoded output (not raw)
    string encryptedBase64 = Convert.ToBase64String(encryptedRaw);
    // base64_encode($iv . $encrypted) = raw IV bytes + base64 string bytes
    byte[] encryptedBytes = Encoding.UTF8.GetBytes(encryptedBase64);
    byte[] combined = new byte[iv.Length + encryptedBytes.Length];
    Buffer.BlockCopy(iv, 0, combined, 0, iv.Length);
    Buffer.BlockCopy(encryptedBytes, 0, combined, iv.Length, encryptedBytes.Length);
    return Convert.ToBase64String(combined);
}

    // Generate Signature
    public static string GenerateSignature(string csmsId, string msisdn, string sid, string sms, string secretKey)
    {
        var payload = new Dictionary<string, string>
        {
            { "csms_id", csmsId },
            { "msisdn", msisdn },
            { "sid", sid },
            { "sms", sms }
        };

        // Sort keys alphabetically
        var sortedPayload = payload.OrderBy(x => x.Key);

        // Create canonical query string
        var queryString = string.Join("&", sortedPayload.Select(x =>
            $"{x.Key}={Uri.EscapeDataString(x.Value)}"));

        // HMAC SHA256
        using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(secretKey));
        byte[] hash = hmac.ComputeHash(Encoding.UTF8.GetBytes(queryString));

        return Convert.ToHexString(hash).ToLower();
    }

    static async Task Main()
    {
        string apiToken = "YOUR_API_TOKEN";
        string secretKey = "YOUR_SECRET_KEY";
        string sid = "YOUR_SID";
        string msisdn = "01XXXXXXXXX";
        string csmsId = "SSIG-ID-XXX";

        string otpMessage = "Your OTP is 123456";

        // Step 1: Encrypt SMS
        string encryptedSms = EncryptSms(otpMessage, secretKey);

        // Step 2: Generate Signature
        string signature = GenerateSignature(csmsId, msisdn, sid, encryptedSms, secretKey);

        // Step 3: Build request payload
        var payload = new
        {
            api_token = apiToken,
            sid = sid,
            msisdn = msisdn,
            sms = encryptedSms,
            csms_id = csmsId
        };

        var json = JsonSerializer.Serialize(payload);

        using var client = new HttpClient();

        var request = new HttpRequestMessage(HttpMethod.Post,
            "https://smsplus.sslwireless.com/api/v3/secure/otp-sms");

        request.Content = new StringContent(json, Encoding.UTF8, "application/json");

        // Add Signature Header
        request.Headers.Add("X-Signature", signature);

        var response = await client.SendAsync(request);

        string result = await response.Content.ReadAsStringAsync();

        Console.WriteLine("Response:");
        Console.WriteLine(result);
    }
}
Java (HttpClient) - Secure OTP + Signature
package smsplus;


import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Map;
import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;


public class SecureOtpSignatureSms {


    public static String encryptSms(String plainText, String secretKey) throws Exception {
        // STEP 1: hash('sha256', secretKey) → 64-character hex string
        String keyHex = sha256Hex(secretKey);
        byte[] keyBytes = keyHex.getBytes(StandardCharsets.UTF_8); 


        // STEP 2: generate 16-byte IV
        byte[] iv = new byte[16];
        new SecureRandom().nextBytes(iv);


        // STEP 3: AES-256-CBC encryption with PKCS5Padding (equivalent to PKCS7)
        Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
        SecretKeySpec keySpec = new SecretKeySpec(keyBytes, 0, 32, "AES"); // only first 32 bytes used
        IvParameterSpec ivSpec = new IvParameterSpec(iv);


        cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8));


        // STEP 4: base64 encode encrypted ciphertext
        String base64Encrypted = Base64.getEncoder().encodeToString(encryptedBytes);


        // STEP 5: prepend IV (raw) + then base64 encode the whole thing
        byte[] combined = new byte[iv.length + base64Encrypted.getBytes(StandardCharsets.UTF_8).length];
        System.arraycopy(iv, 0, combined, 0, iv.length);
        System.arraycopy(base64Encrypted.getBytes(StandardCharsets.UTF_8), 0, combined, iv.length, base64Encrypted.getBytes(StandardCharsets.UTF_8).length);


        return Base64.getEncoder().encodeToString(combined);
    }


    private static String sha256Hex(String input) throws Exception {
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        byte[] hash = digest.digest(input.getBytes(StandardCharsets.UTF_8));
        StringBuilder hexString = new StringBuilder();
        for (byte b : hash) hexString.append(String.format("%02x", b));
        return hexString.toString();
    }


    // Generate HMAC-SHA256 signature (new logic)
    public static String generateSignature(String csmsId, String msisdn, String sid, String sms, String secretKey) throws Exception {
        // Step 1: Build payload map
        Map<String, String> payload = new TreeMap<>(); // TreeMap = sorted by key
        payload.put("csms_id", csmsId);
        payload.put("msisdn", msisdn);
        payload.put("sid", sid);
        payload.put("sms", sms);


        // Step 2: Build URL-encoded query string
        String queryString = payload.entrySet().stream()
                .map(e -> e.getKey() + "=" + URLEncoder.encode(e.getValue(), StandardCharsets.UTF_8))
                .collect(Collectors.joining("&"));


        // Step 3: HMAC-SHA256
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
        mac.init(secretKeySpec);
        byte[] hash = mac.doFinal(queryString.getBytes(StandardCharsets.UTF_8));


        // Step 4: Convert to lowercase hex
        StringBuilder sb = new StringBuilder();
        for (byte b : hash) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }


    public static void main(String[] args) throws Exception {
        String apiToken = "YOUR_API_TOKEN";
        String secretKey = "YOUR_SECRET_KEY";
        String sid = "YOUR_SID";
        String msisdn = "01XXXXXXXXX";
        String csmsId = "SSIG-ID-XXX";
        String url = "https://smsplus.sslwireless.com/api/v3/secure/otp-sms";


        // Step 1: Encrypt the OTP message
        String encryptedSms = encryptSms("Your OTP is 123456", secretKey);


        // Step 2: Generate signature using new logic
        String signature = generateSignature(csmsId, msisdn, sid, encryptedSms, secretKey);


        // Step 3: Build JSON payload
        String json = String.format(
                "{\"api_token\":\"%s\",\"sid\":\"%s\",\"msisdn\":\"%s\",\"sms\":\"%s\",\"csms_id\":\"%s\"}",
                apiToken, sid, msisdn, encryptedSms, csmsId
        );


        // Step 4: Send HTTP POST request
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/json")
                .header("X-Signature", signature)
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();


        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}
PHP - Bulk SMS
<?php
$data = [
    "api_token"     => "***YOUR_API_TOKEN***",
    "sid"           => "***YOUR_SID***",
    "msisdn"        => ["01XXXXXXXXX","01XXXXXXXXX","01XXXXXXXXX"],
    "sms"           => "Bulk SMS message content",
    "batch_csms_id" => "BATCH-001"
];
$ch = curl_init("https://smsplus.sslwireless.com/api/v3/send-sms/bulk");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$res = json_decode(curl_exec($ch), true);
curl_close($ch);
print_r($res);
Python (Requests) - Bulk SMS
import requests

data = {
    "api_token": "***YOUR_API_TOKEN***",
    "sid": "***YOUR_SID***",
    "msisdn": ["01XXXXXXXXX", "01XXXXXXXXX", "01XXXXXXXXX"],
    "sms": "Bulk SMS message content",
    "batch_csms_id": "BATCH-001"
}

response = requests.post(
    "https://smsplus.sslwireless.com/api/v3/send-sms/bulk",
    json=data
)
print(response.json())
Node.js (Fetch) - Bulk SMS
const data = {
  api_token: "***YOUR_API_TOKEN***",
  sid: "***YOUR_SID***",
  msisdn: ["01XXXXXXXXX", "01XXXXXXXXX", "01XXXXXXXXX"],
  sms: "Bulk SMS message content",
  batch_csms_id: "BATCH-001"
};

fetch("https://smsplus.sslwireless.com/api/v3/send-sms/bulk", {
  method: "POST",
  headers: {"Content-Type": "application/json"},
  body: JSON.stringify(data)
}).then(r => r.json()).then(console.log);
Go (net/http) - Bulk SMS
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	data := map[string]interface{}{
		"api_token":     "***YOUR_API_TOKEN***",
		"sid":           "***YOUR_SID***",
		"msisdn":        []string{"01XXXXXXXXX", "01XXXXXXXXX", "01XXXXXXXXX"},
		"sms":           "Bulk SMS message content",
		"batch_csms_id": "BATCH-001",
	}

	jsonData, _ := json.Marshal(data)
	resp, err := http.Post(
		"https://smsplus.sslwireless.com/api/v3/send-sms/bulk",
		"application/json",
		bytes.NewBuffer(jsonData),
	)
	if err != nil {
		fmt.Println("Request error:", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
C# (.NET HttpClient) - Bulk SMS
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program {
    static async Task Main() {
        var data = new {
            api_token = "***YOUR_API_TOKEN***",
            sid = "***YOUR_SID***",
            msisdn = new[] {"01XXXXXXXXX", "01XXXXXXXXX", "01XXXXXXXXX"},
            sms = "Bulk SMS message content",
            batch_csms_id = "BATCH-001"
        };

        var client = new HttpClient();
        var json = JsonSerializer.Serialize(data);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        var response = await client.PostAsync(
            "https://smsplus.sslwireless.com/api/v3/send-sms/bulk", content);
        Console.WriteLine(await response.Content.ReadAsStringAsync());
    }
}
Java (HttpClient) - Bulk SMS
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.util.List;
import java.util.Map;

public class BulkSms {
    public static void main(String[] args) throws Exception {
        String url = "https://smsplus.sslwireless.com/api/v3/send-sms/bulk";

        String json = String.format(
            "{\"api_token\":\"%s\",\"sid\":\"%s\",\"msisdn\":[\"%s\",\"%s\",\"%s\"],\"sms\":\"%s\",\"batch_csms_id\":\"%s\"}",
            "***YOUR_API_TOKEN***", "***YOUR_SID***",
            "01XXXXXXXXX", "01XXXXXXXXX", "01XXXXXXXXX",
            "Bulk SMS message content", "BATCH-001"
        );

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}
PHP - Dynamic SMS
<?php
$data = [
    "api_token" => "***YOUR_API_TOKEN***",
    "sid"       => "***YOUR_SID***",
    "sms"       => [
        ["msisdn"=>"01XXXXXXXXX","text"=>"Hello John!","csms_id"=>"DYN-001"],
        ["msisdn"=>"01XXXXXXXXX","text"=>"Hello Jane!","csms_id"=>"DYN-002"]
    ]
];
$ch = curl_init("https://smsplus.sslwireless.com/api/v3/send-sms/dynamic");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
curl_setopt($ch, CURLOPT_HTTPHEADER, ["Content-Type: application/json"]);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
echo curl_exec($ch);
curl_close($ch);
Python (Requests) - Dynamic SMS
import requests

data = {
    "api_token": "***YOUR_API_TOKEN***",
    "sid": "***YOUR_SID***",
    "sms": [
        {
            "msisdn": "01XXXXXXXXX",
            "text": "Hello John!",
            "csms_id": "DYN-001"
        },
        {
            "msisdn": "01XXXXXXXXX",
            "text": "Hello Jane!",
            "csms_id": "DYN-002"
        }
    ]
}

response = requests.post(
    "https://smsplus.sslwireless.com/api/v3/send-sms/dynamic",
    json=data
)
print(response.json())
Node.js (Fetch) - Dynamic SMS
const data = {
  api_token: "***YOUR_API_TOKEN***",
  sid: "***YOUR_SID***",
  sms: [
    {
      msisdn: "01XXXXXXXXX",
      text: "Hello John!",
      csms_id: "DYN-001"
    },
    {
      msisdn: "01XXXXXXXXX",
      text: "Hello Jane!",
      csms_id: "DYN-002"
    }
  ]
};

fetch("https://smsplus.sslwireless.com/api/v3/send-sms/dynamic", {
  method: "POST",
  headers: {"Content-Type": "application/json"},
  body: JSON.stringify(data)
}).then(r => r.json()).then(console.log);
Bash (cURL) - Dynamic SMS
curl -X POST https://smsplus.sslwireless.com/api/v3/send-sms/dynamic \
  -H 'Content-Type: application/json' \
  -d '{
  "api_token": "***YOUR_API_TOKEN***",
  "sid": "***YOUR_SID***",
  "sms": [
    {"msisdn":"01XXXXXXXXX","text":"Hello John!","csms_id":"DYN-001"},
    {"msisdn":"01XXXXXXXXX","text":"Hello Jane!","csms_id":"DYN-002"}
  ]
}'
Go (net/http) - Dynamic SMS
package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
)

func main() {
	data := map[string]interface{}{
		"api_token": "***YOUR_API_TOKEN***",
		"sid":       "***YOUR_SID***",
		"sms": []map[string]string{
			{"msisdn": "01XXXXXXXXX", "text": "Hello John!", "csms_id": "DYN-001"},
			{"msisdn": "01XXXXXXXXX", "text": "Hello Jane!", "csms_id": "DYN-002"},
		},
	}

	jsonData, _ := json.Marshal(data)
	resp, err := http.Post(
		"https://smsplus.sslwireless.com/api/v3/send-sms/dynamic",
		"application/json",
		bytes.NewBuffer(jsonData),
	)
	if err != nil {
		fmt.Println("Request error:", err)
		return
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)
	fmt.Println(string(body))
}
C# (.NET HttpClient) - Dynamic SMS
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;

class Program {
    static async Task Main() {
        var data = new {
            api_token = "***YOUR_API_TOKEN***",
            sid = "***YOUR_SID***",
            sms = new[] {
                new {
                    msisdn = "01XXXXXXXXX",
                    text = "Hello John!",
                    csms_id = "DYN-001"
                },
                new {
                    msisdn = "01XXXXXXXXX",
                    text = "Hello Jane!",
                    csms_id = "DYN-002"
                }
            }
        };

        var client = new HttpClient();
        var json = JsonSerializer.Serialize(data);
        var content = new StringContent(json, Encoding.UTF8, "application/json");

        var response = await client.PostAsync(
            "https://smsplus.sslwireless.com/api/v3/send-sms/dynamic", content);
        Console.WriteLine(await response.Content.ReadAsStringAsync());
    }
}
Java (HttpClient) - Dynamic SMS
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class DynamicSms {
    public static void main(String[] args) throws Exception {
        String url = "https://smsplus.sslwireless.com/api/v3/send-sms/dynamic";

        String json = String.format(
            "{\"api_token\":\"%s\",\"sid\":\"%s\",\"sms\":[{\"msisdn\":\"%s\",\"text\":\"%s\",\"csms_id\":\"%s\"},{\"msisdn\":\"%s\",\"text\":\"%s\",\"csms_id\":\"%s\"}]}",
            "***YOUR_API_TOKEN***", "***YOUR_SID***",
            "01XXXXXXXXX", "Hello John!", "DYN-001",
            "01XXXXXXXXX", "Hello Jane!", "DYN-002"
        );

        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(json))
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.body());
    }
}