SMSlenz home

WooCommerce & WordPress Integration

smslenz.lk offers a dedicated WooCommerce add-on plugin, so you can add SMS notifications to your WordPress store. Send automated SMS updates to customers for purchase events and keep them informed at every step.

Download SMSlenz for WooCommerce and start sending SMS notifications from your WordPress-powered store today.

smslenz for wordpress

REST API Endpoint Guide

Need to integrate SMSlenz.lk with your custom development? We provide a complete guide to our direct API endpoints: call them from your application and start using our SMS services instantly.

Our API supports all major programming languages, including PHP, JavaScript, Python, Java, C#, Ruby, Go, and Node.js. It works with any type of application, whether it’s a web platform, desktop software, or mobile app (Android or iOS).

Direct Endpoints for smslenz.lk SMS Actions

  1. Send SMS
  2. Send Bulk SMS
  3. Account Status
  4. Save Contact
  5. Reload Credit
  6. Payment Status

Send SMS

POSTGET

Use this endpoint directly to send SMS to a contact number.

Request

URL: https://mail.smslenz.lk/api/send-sms

Parameters
Key Required Value
user_id Required User ID from your settings page.
api_key Required API key from your settings page.
sender_id Required Your approved Sender ID. Use SMSlenzDEMO for testing. This one is case sensitive.
contact Required The recipient, Should be in the format of +9476XXXXXXX.
message Required The message. Max: 1500 chars.
contact_name Optional Name to save with the contact (max 255 chars). Only applied when the contact is new or has no name yet, so names you edited in your dashboard are never overwritten.
Sample Request Body (POST · JSON)
JSON
{
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "sender_id": "SMSlenzDEMO",
    "contact": "+9476XXXXXXX",
    "message": "Welcome to SMSlenz!",
    "contact_name": "Kamal"
}
Sample GET Request URL
URL
https://mail.smslenz.lk/api/send-sms?user_id=12&api_key=YOUR_API_KEY&sender_id=SMSlenzDEMO&contact=%2B9476XXXXXXX&message=Welcome%20to%20SMSlenz%21

Query values must be URL-encoded — note the + in the contact number is sent as %2B.

Code Examples
cURL
curl -X POST "https://mail.smslenz.lk/api/send-sms" \
  -d "user_id=12" \
  -d "api_key=YOUR_API_KEY" \
  -d "sender_id=SMSlenzDEMO" \
  -d "contact=+9476XXXXXXX" \
  -d "message=Welcome to SMSlenz!"
PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://mail.smslenz.lk/api/send-sms");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'user_id'   => '12',
    'api_key'   => 'YOUR_API_KEY',
    'sender_id' => 'SMSlenzDEMO',
    'contact'   => '+9476XXXXXXX',
    'message'   => 'Welcome to SMSlenz!',
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

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

echo $response;
JavaScript
fetch("https://mail.smslenz.lk/api/send-sms", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        user_id: "12",
        api_key: "YOUR_API_KEY",
        sender_id: "SMSlenzDEMO",
        contact: "+9476XXXXXXX",
        message: "Welcome to SMSlenz!"
    })
})
    .then(res => res.json())
    .then(data => console.log(data))
    .catch(err => console.error(err));
Python
import requests

url = "https://mail.smslenz.lk/api/send-sms"
payload = {
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "sender_id": "SMSlenzDEMO",
    "contact": "+9476XXXXXXX",
    "message": "Welcome to SMSlenz!"
}

response = requests.post(url, data=payload)
print(response.json())
Response

You will get a JSON response in a success attempt.

Content-Type: application/json

Body:

JSON
{
    "success": true,
    "message": "SMS sent successfully",
    "data": {
        "status": "success",
        "campaign_id": 42,
        "message": "Welcome to SMSlenz!",
        "sender_id": "SMSlenzDEMO",
        "pages": 1,
        "recipient_number": "9475XXXXXXX",
        "sms_credit_balance": "2,513.95",
        "charged_from": "main"
    }
}

sms_credit_balance is the remaining balance of the pool the sender ID draws from: its allocated credit when the sender has an active credit allocation, otherwise your main balance. charged_from tells you which (allocation or main).

Send Bulk SMS

POST

Use this endpoint directly to send SMS to multiple contact numbers.

Request

URL: https://mail.smslenz.lk/api/send-bulk-sms

Parameters
Key Required Value
user_id Required User ID from your settings page.
api_key Required API key from your settings page.
sender_id Required Your approved Sender ID. Use SMSlenzDEMO for testing. This one is case sensitive.
contacts Required The number of the recipients, Should be in the format of array
["+9476XXXXXXX","+9475XXXXXXX"].
message Required The message. Max: 1500 chars.
Sample Request Body (POST · JSON)
JSON
{
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "sender_id": "SMSlenzDEMO",
    "contacts": ["+9476XXXXXXX", "+9475XXXXXXX"],
    "message": "Welcome to bulk sms API!"
}

This endpoint accepts POST only — send the body as JSON (Content-Type: application/json) or as regular form fields.

Code Examples
cURL
curl -X POST "https://mail.smslenz.lk/api/send-bulk-sms" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "sender_id": "SMSlenzDEMO",
    "contacts": ["+9476XXXXXXX", "+9475XXXXXXX"],
    "message": "Welcome to bulk sms API!"
  }'
PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://mail.smslenz.lk/api/send-bulk-sms");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'user_id'   => '12',
    'api_key'   => 'YOUR_API_KEY',
    'sender_id' => 'SMSlenzDEMO',
    'contacts'  => ['+9476XXXXXXX', '+9475XXXXXXX'],
    'message'   => 'Welcome to bulk sms API!',
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

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

echo $response;
JavaScript
fetch("https://mail.smslenz.lk/api/send-bulk-sms", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        user_id: "12",
        api_key: "YOUR_API_KEY",
        sender_id: "SMSlenzDEMO",
        contacts: ["+9476XXXXXXX", "+9475XXXXXXX"],
        message: "Welcome to bulk sms API!"
    })
})
    .then(res => res.json())
    .then(data => console.log(data))
    .catch(err => console.error(err));
Python
import requests

url = "https://mail.smslenz.lk/api/send-bulk-sms"
payload = {
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "sender_id": "SMSlenzDEMO",
    "contacts": ["+9476XXXXXXX", "+9475XXXXXXX"],
    "message": "Welcome to bulk sms API!"
}

response = requests.post(url, json=payload)
print(response.json())
Response

You will get a JSON response in a success attempt.

Content-Type: application/json

Body:

JSON
{
    "success": true,
    "message": "SMS sent successfully",
    "data": {
        "status": "success",
        "campaign_id": 43,
        "message": "Welcome to bulk sms API!",
        "sender_id": "SMSlenzDEMO",
        "pages": 1,
        "no_of_recipients": 2,
        "sms_credit_balance": "2,512.77",
        "charged_from": "main"
    }
}

sms_credit_balance is the remaining balance of the pool the sender ID draws from: its allocated credit when the sender has an active credit allocation, otherwise your main balance. charged_from tells you which (allocation or main).

Account Status

POSTGET

Use this endpoint to check the status of your account.

Request

URL: https://mail.smslenz.lk/api/account-status

Parameters
Key Required Value
user_id Required User ID from your settings page.
api_key Required API key from your settings page.
Sample Request Body (POST · JSON)
JSON
{
    "user_id": "12",
    "api_key": "YOUR_API_KEY"
}
Sample GET Request URL
URL
https://mail.smslenz.lk/api/account-status?user_id=12&api_key=YOUR_API_KEY
Code Examples
cURL
curl -X POST "https://mail.smslenz.lk/api/account-status" \
  -d "user_id=12" \
  -d "api_key=YOUR_API_KEY"
PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://mail.smslenz.lk/api/account-status");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'user_id' => '12',
    'api_key' => 'YOUR_API_KEY',
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

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

echo $response;
JavaScript
fetch("https://mail.smslenz.lk/api/account-status", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        user_id: "12",
        api_key: "YOUR_API_KEY"
    })
})
    .then(res => res.json())
    .then(data => console.log(data))
    .catch(err => console.error(err));
Python
import requests

url = "https://mail.smslenz.lk/api/account-status"
payload = {
    "user_id": "12",
    "api_key": "YOUR_API_KEY"
}

response = requests.post(url, data=payload)
print(response.json())
Response

You will get a JSON response in a success attempt.

Content-Type: application/json

Body:

JSON
{
    "success": true,
    "message": "Account status retrieved successfully",
    "data": {
        "status": "active",
        "sms_credit_balance": "2,515.72",
        "allocated_credit_total": "1,500.00",
        "sender_id_balances": [
            {
                "sender_id": "YOURBRAND",
                "allocated_balance": "1,500.00",
                "active": true
            }
        ],
        "active_plan": "Pay As You Go",
        "total_contacts": 3,115,
        "total_sender_ids": 6
    }
}

sms_credit_balance is your main balance. sender_id_balances lists sender IDs holding a credit allocation; a sender with an active allocation is charged only from its allocated balance.

Save Contact

POST

Use this endpoint to add a contact to your account without sending an SMS. Saving a number that already exists is safe: you get the existing contact back.

Request

URL: https://mail.smslenz.lk/api/save-contact

Parameters
Key Required Value
user_id Required User ID from your settings page.
api_key Required API key from your settings page.
contact Required A Sri Lankan mobile number, e.g. +9476XXXXXXX or 076XXXXXXX.
name Optional Contact name (max 255 chars). Only applied when the contact is new or has no name yet.
group Optional A contact group name (max 255 chars). The contact is added to it, and the group is created if you don't have it yet. Every contact is also added to "All Contacts".
Sample Request Body (POST · JSON)
JSON
{
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "contact": "+9476XXXXXXX",
    "name": "Kamal Perera",
    "group": "VIP Customers"
}
Code Examples
cURL
curl -X POST "https://mail.smslenz.lk/api/save-contact" \
  -d "user_id=12" \
  -d "api_key=YOUR_API_KEY" \
  --data-urlencode "contact=+9476XXXXXXX" \
  --data-urlencode "name=Kamal Perera" \
  --data-urlencode "group=VIP Customers"
PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://mail.smslenz.lk/api/save-contact");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'user_id' => '12',
    'api_key' => 'YOUR_API_KEY',
    'contact' => '+9476XXXXXXX',
    'name'    => 'Kamal Perera',
    'group'   => 'VIP Customers',
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

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

echo $response;
JavaScript
fetch("https://mail.smslenz.lk/api/save-contact", {
    method: "POST",
    headers: { "Content-Type": "application/json", "Accept": "application/json" },
    body: JSON.stringify({
        user_id: "12",
        api_key: "YOUR_API_KEY",
        contact: "+9476XXXXXXX",
        name: "Kamal Perera",
        group: "VIP Customers"
    })
})
    .then(res => res.json())
    .then(data => console.log(data))
    .catch(err => console.error(err));
Python
import requests

url = "https://mail.smslenz.lk/api/save-contact"
payload = {
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "contact": "+9476XXXXXXX",
    "name": "Kamal Perera",
    "group": "VIP Customers"
}

response = requests.post(url, data=payload)
print(response.json())
Response

HTTP 201 when a new contact was created, 200 when the number was already in your contacts.

Content-Type: application/json

Body:

JSON
{
    "success": true,
    "message": "Contact saved successfully",
    "data": {
        "contact_id": 1024,
        "name": "Kamal Perera",
        "phone": "+9476XXXXXXX",
        "created": true,
        "groups": ["All Contacts", "VIP Customers"]
    }
}

groups lists every group the contact belongs to.

Errors
HTTP status Meaning
400 Invalid contact number format.
401 Invalid API key or user ID.
403 Your account is suspended.
422 A parameter is missing or invalid. The errors field says which.
429 Too many requests. Please slow down.

Reload Credit

POST

Use this endpoint to top up your SMS credit from your own system. It creates a payment link; whoever pays (you, your staff or your customer) opens it and pays by card on PayHere's secure checkout. Card details never pass through your system or ours.

How it works
  1. Call this endpoint. You get an order_id and a payment_url.
  2. Open the payment_url in a browser, or redirect your user to it. It takes them to card checkout. No SMSlenz login is needed.
  3. Get the result: pass a callback_url and we'll POST it to your server (see Payment Callbacks), or check Payment Status. The credit is added to your account as soon as the payment completes.
Request

URL: https://mail.smslenz.lk/api/reload-credit

Parameters
Key Required Value
user_id Required User ID from your settings page.
api_key Required API key from your settings page.
amount Required Amount to reload in rupees, as a whole number between 1000 and 100000.
sender_id Optional One of your approved Sender IDs. Once paid, the whole amount is allocated to this sender instead of your main balance. Case sensitive.
client_reference Optional Your own reference, such as an invoice number (max 64 chars). Sending the same value again returns the existing payment link instead of creating a new one, so retrying a request is safe.
return_url Optional An https:// page to send the payer back to after paying or cancelling. Without it, they see an SMSlenz confirmation page.
callback_url Optional A public https:// URL on your server. We POST the result to it when this payment is paid or its link expires. See Payment Callbacks.
Sample Request Body (POST · JSON)
JSON
{
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "amount": 5000,
    "sender_id": "YOURBRAND",
    "client_reference": "INV-1001",
    "return_url": "https://example.com/payment-complete",
    "callback_url": "https://example.com/smslenz-callback"
}

This endpoint accepts POST only — send the body as JSON (Content-Type: application/json) or as regular form fields.

Code Examples
cURL
curl -X POST "https://mail.smslenz.lk/api/reload-credit" \
  -H "Content-Type: application/json" \
  -d '{
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "amount": 5000,
    "client_reference": "INV-1001",
    "callback_url": "https://example.com/smslenz-callback"
  }'
PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://mail.smslenz.lk/api/reload-credit");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode([
    'user_id'          => '12',
    'api_key'          => 'YOUR_API_KEY',
    'amount'           => 5000,
    'client_reference' => 'INV-1001',
    'callback_url'     => 'https://example.com/smslenz-callback',
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

// Save $response['data']['order_id'], then send the payer to checkout:
header('Location: ' . $response['data']['payment_url']);
JavaScript
fetch("https://mail.smslenz.lk/api/reload-credit", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        user_id: "12",
        api_key: "YOUR_API_KEY",
        amount: 5000,
        client_reference: "INV-1001",
        callback_url: "https://example.com/smslenz-callback"
    })
})
    .then(res => res.json())
    .then(data => {
        // Save data.data.order_id, then open checkout
        window.location.href = data.data.payment_url;
    })
    .catch(err => console.error(err));
Python
import requests

url = "https://mail.smslenz.lk/api/reload-credit"
payload = {
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "amount": 5000,
    "client_reference": "INV-1001",
    "callback_url": "https://example.com/smslenz-callback"
}

data = requests.post(url, json=payload).json()
print(data["data"]["order_id"], data["data"]["payment_url"])
Response

You will get a JSON response with status 201 when a new link is created, or 200 when client_reference matches an existing one.

Content-Type: application/json

Body:

JSON
{
    "success": true,
    "message": "Payment link created",
    "data": {
        "order_id": "PRU3FTX7HUJP8RAHY4",
        "amount": "5,000.00",
        "status": "pending",
        "last_attempt": null,
        "client_reference": "INV-1001",
        "sender_id": "YOURBRAND",
        "allocation_status": null,
        "callback_url": "https://example.com/smslenz-callback",
        "expires_at": "2026-10-08T15:30:00+05:30",
        "paid_at": null,
        "payment_url": "https://mail.smslenz.lk/pay/PRU3FTX7HUJP8RAHY4?signature=3f9c…"
    }
}
  • The payment_url works for 60 minutes (until expires_at). If a payment is cancelled or declined, the same link can be opened again to retry.
  • With a return_url, the payer is sent back to it with ?order_id=…&status=… added. Treat that as a hint only: rely on your callback or Payment Status before acting on it.
Errors
HTTP status Meaning
401 Invalid API key or user ID.
403 Your account is suspended.
409 The client_reference was already used for a different amount or sender ID.
422 A parameter is invalid, your account has no active package, or the sender ID can't receive credit. The message field says which.
429 Too many requests. You can create up to 10 payment links per minute.

Payment Status

POST

Use this endpoint to check whether a Reload Credit payment has completed. If you don't use a callback_url, check after the payer returns from checkout, and keep checking every few seconds until the status is paid or expired.

Request

URL: https://mail.smslenz.lk/api/payment-status

Parameters
Key Required Value
user_id Required User ID from your settings page.
api_key Required API key from your settings page.
order_id Required The order_id returned by Reload Credit.
Sample Request Body (POST · JSON)
JSON
{
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "order_id": "PRU3FTX7HUJP8RAHY4"
}
Code Examples
cURL
curl -X POST "https://mail.smslenz.lk/api/payment-status" \
  -d "user_id=12" \
  -d "api_key=YOUR_API_KEY" \
  -d "order_id=PRU3FTX7HUJP8RAHY4"
PHP
<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://mail.smslenz.lk/api/payment-status");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query([
    'user_id'  => '12',
    'api_key'  => 'YOUR_API_KEY',
    'order_id' => 'PRU3FTX7HUJP8RAHY4',
]));
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

$response = json_decode(curl_exec($ch), true);
curl_close($ch);

if ($response['data']['status'] === 'paid') {
    // Credit has been added to your account
}
JavaScript
fetch("https://mail.smslenz.lk/api/payment-status", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
        user_id: "12",
        api_key: "YOUR_API_KEY",
        order_id: "PRU3FTX7HUJP8RAHY4"
    })
})
    .then(res => res.json())
    .then(data => console.log(data.data.status))
    .catch(err => console.error(err));
Python
import requests

url = "https://mail.smslenz.lk/api/payment-status"
payload = {
    "user_id": "12",
    "api_key": "YOUR_API_KEY",
    "order_id": "PRU3FTX7HUJP8RAHY4"
}

response = requests.post(url, data=payload)
print(response.json()["data"]["status"])
Response

You will get a JSON response in a success attempt.

Content-Type: application/json

Body:

JSON
{
    "success": true,
    "message": "Payment status retrieved successfully",
    "data": {
        "order_id": "PRU3FTX7HUJP8RAHY4",
        "amount": "5,000.00",
        "status": "paid",
        "last_attempt": null,
        "client_reference": "INV-1001",
        "sender_id": "YOURBRAND",
        "allocation_status": "allocated",
        "callback_url": "https://example.com/smslenz-callback",
        "expires_at": "2026-10-08T15:30:00+05:30",
        "paid_at": "2026-10-08T14:42:10+05:30",
        "callback_status": "delivered",
        "sms_credit_balance": "2,515.72",
        "sender_id_balance": "6,500.00"
    }
}
Field Meaning
status pending (not paid yet), paid (credit added), or expired (the link ran out unpaid — create a new one).
last_attempt While pending: cancelled or failed if the payer's last try didn't go through, otherwise null.
allocation_status When a sender_id was given: allocated, or skipped if the sender couldn't receive credit by the time the payment completed (the credit went to your main balance instead).
callback_status When a callback_url was given: pending (being sent or retried), delivered, or failed (gave up after the last retry). null until there is something to send.
sms_credit_balance Your main balance now.
sender_id_balance Only when a sender_id was given: that sender's allocated balance now.

Unknown order IDs, and orders belonging to another account, return 404.

Payment Callbacks

POST

Pass a callback_url to Reload Credit and we'll POST the result to your server when that payment is paid or its link expires, so you don't need to keep checking Payment Status. Each payment can use a different callback_url.

Events
Event Sent when
payment.paid The payment completed and the credit was added (or allocated).
payment.expired The payment link ran out without being paid.
What we send

A POST with a JSON body (Content-Type: application/json) and these headers:

Header Value
X-SMSlenz-Event The event, e.g. payment.paid.
X-SMSlenz-Event-Id Unique per event. Retries of the same event reuse it.
X-SMSlenz-Signature t=<unix timestamp>,v1=<signature> — see Verifying a callback below.
JSON
{
    "event": "payment.paid",
    "event_id": "evt_01k6ztg3m8q2v7r4c1x9n5b0wd",
    "created_at": "2026-10-08T14:42:11+05:30",
    "data": {
        "order_id": "PRU3FTX7HUJP8RAHY4",
        "amount": "5,000.00",
        "status": "paid",
        "last_attempt": null,
        "client_reference": "INV-1001",
        "sender_id": "YOURBRAND",
        "allocation_status": "allocated",
        "callback_url": "https://example.com/smslenz-callback",
        "expires_at": "2026-10-08T15:30:00+05:30",
        "paid_at": "2026-10-08T14:42:10+05:30",
        "sms_credit_balance": "2,515.72",
        "sender_id_balance": "6,500.00"
    }
}

data has the same fields as the Payment Status response.

Responding
  • Reply with any 2xx status within 10 seconds. Do slow work after replying.
  • Anything else is retried after 1 minute, 5 minutes, 30 minutes, 2 hours and 6 hours, then we stop. Redirects are not followed.
  • The same event can arrive more than once. Process each event_id only once.
  • Payment Status is always the source of truth, so you can still check it if a callback doesn't arrive.
Verifying a callback

The v1 signature is an HMAC-SHA256 of {t}.{raw request body}, keyed with your API key. Compute it yourself and compare; also reject callbacks whose t is more than 5 minutes old. If you regenerate your API key, callbacks sent after that are signed with the new key.

PHP
<?php
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_X_SMSLENZ_SIGNATURE'] ?? ''), $sig);

$expected = hash_hmac('sha256', ($sig['t'] ?? '') . '.' . $body, 'YOUR_API_KEY');

if (! hash_equals($expected, $sig['v1'] ?? '') || abs(time() - (int) ($sig['t'] ?? 0)) > 300) {
    http_response_code(400);
    exit;
}

$event = json_decode($body, true);
// Skip $event['event_id'] if you've already processed it, then:
if ($event['event'] === 'payment.paid') {
    // $event['data']['order_id'] is paid
}

http_response_code(200);
Node.js
const crypto = require("crypto");
const express = require("express");
const app = express();

// Use the raw body: the signature covers the exact bytes we sent.
app.post("/smslenz-callback", express.raw({ type: "application/json" }), (req, res) => {
    const sig = Object.fromEntries(
        (req.get("X-SMSlenz-Signature") || "").split(",").map(part => part.split("="))
    );
    const expected = crypto.createHmac("sha256", "YOUR_API_KEY")
        .update(`${sig.t}.${req.body}`)
        .digest("hex");

    const valid = sig.v1 && sig.v1.length === expected.length
        && crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig.v1))
        && Math.abs(Date.now() / 1000 - Number(sig.t)) <= 300;
    if (!valid) return res.sendStatus(400);

    const event = JSON.parse(req.body);
    // Skip event.event_id if you've already processed it, then handle event.event
    res.sendStatus(200);
});
Python
import hashlib, hmac, json, time
from flask import Flask, abort, request

app = Flask(__name__)

@app.post("/smslenz-callback")
def smslenz_callback():
    body = request.get_data()  # raw bytes, exactly as sent
    sig = dict(part.split("=", 1) for part in request.headers.get("X-SMSlenz-Signature", "").split(",") if "=" in part)

    expected = hmac.new(b"YOUR_API_KEY", f"{sig.get('t')}.".encode() + body, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(expected, sig.get("v1", "")) or abs(time.time() - int(sig.get("t", 0))) > 300:
        abort(400)

    event = json.loads(body)
    # Skip event["event_id"] if you've already processed it, then handle event["event"]
    return "", 200

Find your user ID and API key on the API Settings page.

See something missing? Contact us and let us know. We are always happy to help with integrations.

Integrations

smslenz php integration smslenz woocommerce integration smslenz nodejs integration smslenz zapier integration smslenz java integration smslenz python integration smslenz csharp integration