Skip to content
SMSRay

Developer hub

Ship SMS before your coffee cools

Five REST endpoints, one auth header, one error shape. Send messages and one-time passwords to Nepal from any language that can make an HTTPS request.

Base URL

https://api.smsray.in/api/sms/v1

Auth

x-api-key: <your key>

Errors

{ "error", "code", "details"? }

Quickstart

Three steps to your first message

  1. Step 1

    Create a workspace

    Sign in at app.smsray.in with your phone number or email. New workspaces start as pending until our team activates them.

  2. Step 2

    Create an API key in Clients

    Open Clients, add one per app or environment, and copy the key and webhook secret — they're shown once and stored only as hashes.

  3. Step 3

    Send

    POST to /sms/send with the x-api-key header. You get a messageId back instantly and the status follows.

Send an SMS

One POST. The reply carries the messageId, segment count and encoding.

curl https://api.smsray.in/api/sms/v1/sms/send \
  -H "x-api-key: $SMSRAY_API_KEY" \
  -H "content-type: application/json" \
  -H "Idempotency-Key: order-1042-shipped" \
  -d '{ "to": "9779801234567", "text": "Your order #1042 has shipped." }'

Verify a phone number

We generate the code, send it and check it. Valid 5 minutes, 5 attempts.

# 1. Send a code (6 digits, valid 5 minutes)
curl https://api.smsray.in/api/sms/v1/sms/otp/send \
  -H "x-api-key: $SMSRAY_API_KEY" -H "content-type: application/json" \
  -d '{ "to": "9779801234567", "purpose": "login", "ip": "203.0.113.7" }'

# 2. Check what the user typed
curl https://api.smsray.in/api/sms/v1/sms/otp/verify \
  -H "x-api-key: $SMSRAY_API_KEY" -H "content-type: application/json" \
  -d '{ "to": "9779801234567", "purpose": "login", "code": "482913" }'
MethodPathWhat it does
POST/sms/sendSend a transactional, OTP or promotional message
POST/sms/otp/sendGenerate and send a 6-digit code
POST/sms/otp/verifyCheck the code your user typed
GET/sms/messages/:idLook up a message and its status
GET/sms/balanceWorkspace balance, rates and your counters

Webhooks

Verify every event in a few lines

Each delivery carries x-lacspace-signature: t=…,v1=… — an HMAC-SHA256 of the timestamp and raw body with your webhook secret.

  • Events: message.status and message.inbound
  • Reject timestamps outside ±300 s to stop replays
  • During secret rotation two v1 values are sent — accept either
  • 8 attempts with backoff: 10 s, 30 s, 2 min, 10 min, 30 min, 1 h, 3 h, 6 h
  • Respond 2xx within 10 s; use x-lacspace-delivery to de-duplicate
Webhook reference
import crypto from "node:crypto";

// x-lacspace-signature: t=<unix>,v1=<hex>[,v1=<hex during secret rotation>]
export function verifySmsrayWebhook(rawBody, header, secret, toleranceSec = 300) {
  const pairs = header.split(",").map((p) => p.split("="));
  const t = Number(pairs.find(([k]) => k === "t")?.[1]);
  if (!t || Math.abs(Date.now() / 1000 - t) > toleranceSec) return false;
  const expected = Buffer.from(
    crypto.createHmac("sha256", secret).update(`${t}.${rawBody}`).digest("hex"), "hex");
  return pairs
    .filter(([k]) => k === "v1")
    .some(([, v]) => {
      const sig = Buffer.from(v, "hex");
      return sig.length === expected.length && crypto.timingSafeEqual(sig, expected);
    });
}

Testing tips

Build it right the first time

Test with your own number

Send to your own Nepal mobile number (96/97/98XXXXXXXX) first and watch the message move in the dashboard. Every send, including tests, is billed from your balance.

Always send an Idempotency-Key

Use something stable like order-1042-shipped. If your job retries, the replay returns the original response with Idempotent-Replayed: true — no second SMS, no second charge.

Poll status while you build

Before your webhook endpoint is live, call GET /sms/messages/:id to follow a message through queued, sent and delivered. Switch to webhooks in production.

Treat a wrong OTP as data

A wrong code returns 200 with verified: false and a reason. Pass the end user's ip on send to turn on per-IP limits.

SDKs

REST-first. Official libraries coming soon.

Today SMSRay is a plain JSON-over-HTTPS API, so it works from any stack with no package to install. The docs show cURL, Node.js, Python and PHP for every endpoint. Official client libraries are on the way.

cURLNode.jsPythonPHPSDKs · soon

Get your API key

Create a workspace with your phone number or email, add a client and send your first message from the terminal.