How it works
From your API call to their screen, step by step
You integrate one REST API. We approve your templates, deliver every message over local mobile networks and report back. Here is what happens to a message, and what you see at each step.
In four steps
Connect, approve, send, track
What you do, and what you see, from the first API key to the delivery receipt.
Step 1 of 4
Connect
We set up your workspace. Create an API key in the dashboard, with scopes, an IP allowlist, a daily cap and test mode, then call one REST endpoint from your server.
curl https://api.smsray.com/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." }'Step 2 of 4
Approve a template
Five templates are ready from day one. Send us your own wording with {{variables}} for the parts that change; we aim to review it within one business day.
Step 3 of 4
Send
One POST with the number and the text. SMSRay checks it against your template, counts the SMS and answers straight away with a message id.
Step 4 of 4
Track
Watch the status move to delivered in the dashboard, poll it by id, or get a signed webhook on your server. Analytics and alerts show the bigger picture.
Automation
How the pieces fit together
Pick an industry to see a typical flow. Steps marked live work today; scheduled sends, keyword auto-replies and webhook-triggered SMS are coming soon.
Confirm every order the moment it is placed and keep your CRM in sync.
Order placed
Your app calls POST /sms/send
Live today“Order confirmed” SMS
Prebuilt approved template
Live todayDelivery report
queued → sent → delivered
Live todayWebhook to your CRM
Signed message.status event
Live today“Out for delivery” on dispatch
Webhook-triggered SMS
Coming soon
The flow
Six steps, every one of them visible
Every message follows the same path. You can watch it in the dashboard, poll it by id, or receive it as a webhook.
- 1
Integrate the API
Create an API key in the dashboard and call our REST API from your server.
x-api-key - 2
Template approval
Custom messages use a template SMSRay has approved. OTP uses our built-in template.
approved - 3
Send
POST /sms/send or /sms/otp/send. We check the number and text, count SMS and reply at once.
queued - 4
Managed delivery
Smart routing across every major mobile network, with automatic retries if an attempt fails.
sent - 5
Reports & webhooks
Delivery reports by API and dashboard, plus a signed message.status webhook.
delivered - 6
Analytics
Volume, delivery and usage for your workspace, in the dashboard.
insights
In plain words
You ask us to send a message from an approved template. We check it, set the cost aside and deliver it. When the network confirms delivery, we tell you.
What you pay for
Each message uses SMS from your plan, by length. If a message finally fails, its cost comes back to your balance automatically. See plans.
What you see
The API answers queued straight away. Later changes arrive as message.status webhooks: sent, delivered, undelivered or failed.
For engineersWhat happens when you call the API
- Authenticate. The
x-api-keyis hashed and matched to your API client. The workspace must be active, the message type allowed on your plan, and the per-client rate limit (20/s by default) not exceeded. - Deduplicate. An
Idempotency-Keyreplay within 24 h returns the original reply instead of sending again. - Validate and reserve. SMSRay delivers to Nepal mobile numbers (96/97/98XXXXXXXX). Text is analysed as GSM-7 or Unicode, up to 6 parts. The cost (rate × SMS used) is reserved from your balance atomically; a short balance returns 402
insufficient_balance. - Deliver. The message is handed to our managed delivery, which delivers it over the recipient's mobile network and retries automatically if an attempt fails.
- Report. Status moves to sent, then delivered or undelivered when the network reports back. A message that cannot be sent ends as failed and its cost is credited back.
- Notify. A webhook delivery is stored, signed with HMAC-SHA256 and posted to your URL; failures retry on a backoff over 8 attempts.
Template approval
Approved once, sent with confidence
Every custom message uses a template approved by SMSRay before it can be sent. It is a quick, one-time step per template, and it keeps spam and phishing off the networks your messages travel on.
OTP works on day one
Codes sent through our OTP API use our built-in template, so there is nothing to submit before your first sign-in code.
Placeholders for the details
A template fixes the wording and leaves room for the parts that change, such as a name, an order number or a date.
Quick review
We aim to review new templates within one business day, and tell you what to change if one isn't approved.
Better for everyone
Review blocks spam before it is sent, which protects deliverability for every sender on the platform.
Starter and Business include OTP and transactional SMS. Promotional SMS is available on Enterprise.
Template · order_shipped · transactional
- Message type matches your plan
- Sender clearly identified
- No misleading or prohibited content
To 98XXXXXXXX
Managed delivery · smart routing · automatic retries
Your app
POST /sms/send
SMSRay
Template check, routing, retries
- NET
Mobile networks
Delivered on any network
Recipient
Message on their phone
Network A
covered
Network B
covered
Network C
covered
Managed delivery
We handle delivery, end to end
Once a message is accepted, SMSRay takes care of getting it to the recipient, whichever mobile network they are on. There is no infrastructure for you to run or monitor.
- Delivered over all mobile networks, built to plug into any carrier
- Smart routing chooses how each message is delivered
- Automatic retries when a delivery attempt fails
- OTPs are sent immediately and never deferred
- Delivery reports for every message, by API, webhook and dashboard
Retries and credits
When an attempt stumbles, we try again
Networks have bad moments. The platform expects them, retries for you and never charges for a message it could not send.
- If an attempt isn't confirmed in time, the message is retried automatically
- If nothing can send it, the message fails and its cost is credited back
- Undelivered messages are not credited: they were sent, but the recipient's phone never confirmed, for example because it stayed off
- Your Idempotency-Key makes your own retries safe: a replay never sends a second SMS
Message 2b1f… · delivery attempts
- timeout
Attempt 1
not confirmed in time
- delivered
Attempt 2
sent → delivered
Message lifecycle
Every status a message can have
These are the statuses you will see from GET /sms/messages/:id and in the dashboard, with the webhook status each one maps to.
queued
Accepted, cost reserved, waiting for delivery.
webhook: — (API reply says queued)
submitting
Being handed to the mobile network.
webhook: queued
submitted
Accepted for delivery.
webhook: sent
sent
On its way to the recipient's phone.
webhook: sent
delivered
The network reported it delivered to the phone.
webhook: delivered
Dashed steps are intermediate and may not appear for every message. Many go from queued straight to sent.
Other outcomes
- undelivered
Sent, but delivery was never confirmed, for example the phone stayed off. Not refunded, because it did go out.
webhook: undelivered
- failed
Could not be sent after automatic retries. Cost credited back.
webhook: failed
- rejected
Refused before sending.
webhook: failed
A status webhook is never sent on accept and never twice for the same status, even if a report arrives late.
Delivery reports and webhooks
Know what happened to every message
Status changes reach your server as signed message.status events, and replies arrive as message.inbound. Verify the signature, update your records, done.
- HMAC-SHA256 signature over timestamp and raw body, checked within ±300 s
- 8 attempts with backoff: 10 s, 30 s, 2 min, 10 min, 30 min, 1 h, 3 h, 6 h
- Never sent twice for the same status
- Or poll any message with GET /sms/messages/:id
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);
});
}Analytics
See volume, delivery outcomes and usage for your workspace in the dashboard, so you know what you send and how it lands.
Searchable message log
Find any message by number or status, see its timeline and send a test, from a laptop or your phone.
Webhook history
Each delivery attempt to your URL is recorded for 7 days, so you can see what reached you and when.
Reliability design
Built so a message is sent once
Double sends are the worst failure in SMS: an OTP twice looks like an attack, a receipt twice looks like a double charge. The platform is designed around preventing them.
Safe on many servers
The API can run as several instances. Background jobs coordinate through the database, never through one process’s memory.
Leases, not hopes
Routing a message and retrying a webhook each take a time-limited lease, so two workers never act on the same item.
Idempotent at every edge
Your Idempotency-Key at the API, deduplication inside delivery, and one webhook per status on the way out.
Fails safe
If a message can’t be sent, it ends as failed with its cost credited back, never stuck in limbo.
Put the flow to work
Talk to sales, get your account and send your first OTP with our built-in template. Every step above shows up live in your dashboard.
Already a customer? Log in