Start typing to search the documentation.

to navigate·to open

API

SMS API

Send SMS programmatically over HTTP — REST (JSON/form), GET query params, or SOAP/XML — with delivery status, discovery, balance, and the full error-code catalogue.

The public SMS API sends DLT-compliant SMS from any external client over plain HTTP, authenticated with a WRNexus API key.

Base URL & authentication

https://app.wrnexus.com

SMS endpoints live under /sms/* (and are aliased under /api/sms/* for REST-convention callers — both resolve to the same handlers).

Authenticate every request with your API key in either header:

Authorization: Bearer wrn_live_<your_api_key>
X-API-Key: wrn_live_<your_api_key>

Scopes: sms:send is required to send; sms:read is required for status and discovery endpoints. A key with no explicit scopes is unrestricted.

The WRNexus SMS model. A message is always sent from a registered sender (from) using an approved template for that sender’s country onboarding. The template’s {{token}} / {#var#} placeholders are filled from your variables (or, for a single-placeholder template, from message). When the sender’s onboarding has exactly one active template, template may be omitted.

Send an SMS

The same logical fields can be sent in any of four interchangeable call styles.

Field Type Notes
from string Required. Sender id or sender header. Aliases: sender, senderId, header.
to string Required. Recipient in E.164 form, e.g. +919812345678. Aliases: recipient, number, msisdn, mobile, phone.
template string Template id or name. Optional when the sender has a single active template. Aliases: templateId, tpl.
message string Convenience body that fills a single-placeholder template. Aliases: text, body, msg, content.
variables object Template token → value map, e.g. { "code": "4821" }.
flash boolean Send as a flash (class-0) SMS. Default false.
scheduledAt string RFC3339 timestamp to queue a future send. Aliases: scheduled_at, schedule, at.

POST /sms/send — REST JSON

curl https://app.wrnexus.com/sms/send \
  -H "Authorization: Bearer wrn_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "from": "ACMEIN",
    "to": "+919812345678",
    "template": "OTP verify",
    "variables": { "code": "4821" }
  }'

Response 200 OK:

{
  "ok": true,
  "status": "queued",
  "messageId": "f58a2939-2c4b-4f0a-9b7e-1f2a3b4c5d6e",
  "to": "+919812345678",
  "from": "ACMEIN",
  "senderId": "snd_01HVZ...",
  "templateId": "tpl_01HVZ...",
  "renderedBody": "Your code is 4821",
  "encoding": "gsm-7",
  "segments": 1,
  "creditsCost": 1,
  "creditsRemaining": 4821,
  "flash": false,
  "scheduledAt": null,
  "createdAt": "2026-06-18T14:30:00.000000"
}

status is queued for an immediate send or scheduled when scheduledAt is in the future. segments/creditsCost reflect the on-wire SMS segment count (160 GSM-7 chars per single segment, 70 for UCS-2).

GET /sms/send — query parameters

Every field is a query parameter — the simplest call style:

curl "https://app.wrnexus.com/sms/send?from=ACMEIN&to=%2B919812345678&message=4821" \
  -H "Authorization: Bearer wrn_live_xxx"

POST /sms/send — form-encoded

Content-Type: application/x-www-form-urlencoded. Pass each variable as var.<token>=value (or a variables= JSON string):

curl https://app.wrnexus.com/sms/send \
  -H "Authorization: Bearer wrn_live_xxx" \
  -d "from=ACMEIN" -d "to=+919812345678" -d "var.code=4821"

POST /sms/soap — SOAP / XML

XML in, XML out, for legacy integrations. Field names mirror the JSON body; the <variables> children are the tokens.

curl https://app.wrnexus.com/sms/soap \
  -H "Authorization: Bearer wrn_live_xxx" \
  -H "Content-Type: application/xml" \
  --data '<SmsRequest>
  <from>ACMEIN</from>
  <to>+919812345678</to>
  <template>OTP verify</template>
  <variables><code>4821</code></variables>
</SmsRequest>'

Response:

<?xml version="1.0" encoding="UTF-8"?>
<SmsResponse>
  <ok>true</ok>
  <status>queued</status>
  <messageId>f58a2939-2c4b-4f0a-9b7e-1f2a3b4c5d6e</messageId>
  <to>+919812345678</to>
  <from>ACMEIN</from>
  <templateId>tpl_01HVZ...</templateId>
  <encoding>gsm-7</encoding>
  <segments>1</segments>
  <creditsCost>1</creditsCost>
  <creditsRemaining>4821</creditsRemaining>
  <renderedBody>Your code is 4821</renderedBody>
  <createdAt>2026-06-18T14:30:00.000000</createdAt>
</SmsResponse>

Errors are returned as the same <SmsResponse> envelope with <ok>false</ok> and an <error><code/><message/></error> block.

Delivery status

GET /sms/status?id=<messageId>

Look up the delivery status of a message you sent (scope sms:read). The alias messageId is also accepted.

curl "https://app.wrnexus.com/sms/status?id=f58a2939-2c4b-4f0a-9b7e-1f2a3b4c5d6e" \
  -H "Authorization: Bearer wrn_live_xxx"
{
  "messageId": "f58a2939-2c4b-4f0a-9b7e-1f2a3b4c5d6e",
  "status": "delivered",
  "to": "+919812345678",
  "renderedBody": "Your code is 4821",
  "encoding": "gsm-7",
  "creditsCost": 1,
  "lastError": null,
  "scheduledAt": null,
  "sentAt": "2026-06-18T14:30:02.000000",
  "createdAt": "2026-06-18T14:30:00.000000"
}

An unknown id returns 404 NOT_FOUND.

Discovery & balance

GET /sms/senders

The organization’s registered senders (scope sms:read).

{
  "senders": [
    {
      "senderId": "snd_01HVZ...",
      "from": "ACMEIN",
      "onboardingId": "onb_01HVZ...",
      "dltSenderId": "1107160000000000000",
      "isActive": true
    }
  ]
}

GET /sms/templates

The organization’s templates and the variables (placeholder tokens) each one requires (scope sms:read).

{
  "templates": [
    {
      "templateId": "tpl_01HVZ...",
      "name": "OTP verify",
      "body": "Your code is {{code}}",
      "variables": ["code"],
      "onboardingId": "onb_01HVZ...",
      "dltTemplateId": "1207160000000000000",
      "isActive": true
    }
  ]
}

GET /sms/balance

Remaining SMS credits for the key’s active workspace (scope sms:read).

{
  "workspaceId": "ws_01HVZ...",
  "creditType": "sms",
  "balance": 4821
}

Identity

GET /api/me

Echoes the identity the key resolves to — useful to verify a key and inspect its scopes and expiry. No scope required. See Authentication for the response shape.

Error responses

Errors use a flat, stable contract:

{
  "code": "INSUFFICIENT_CREDITS",
  "message": "This message costs 1 SMS credit but the workspace only has 0. Top up your SMS credits to send."
}
Code HTTP Description
UNAUTHENTICATED 401 Missing, invalid, expired, or revoked API key.
FORBIDDEN 403 Key lacks the required scope or is not bound to an org.
IP_NOT_ALLOWED 403 Caller IP is not on the organization’s allowlist.
INVALID_SENDER 400 from missing, or no such sender for this organization.
SENDER_INACTIVE 400 The resolved sender is not active.
INVALID_TEMPLATE 400 No such template for this organization.
TEMPLATE_INACTIVE 400 The resolved template is not active.
TEMPLATE_REQUIRED 400 Sender has no single active template — pass template.
TEMPLATE_AMBIGUOUS 400 Sender has several active templates — pass template.
SENDER_TEMPLATE_MISMATCH 400 Sender and template belong to different onboardings.
ONBOARDING_NOT_APPROVED 400 The sender’s country onboarding is not approved yet.
DLT_SENDER_REQUIRED 400 This country needs a DLT sender id on the sender.
DLT_TEMPLATE_REQUIRED 400 This country needs a DLT template id on the template.
INVALID_RECIPIENT 400 to missing or not a valid number for the country.
MISSING_VARIABLES 400 One or more template placeholders have no value.
INVALID_VARIABLES 400 variables is not a JSON object of token → value.
INVALID_SCHEDULED_AT 400 scheduledAt is not an RFC3339 timestamp.
SCHEDULED_AT_IN_PAST 400 scheduledAt is not in the future.
INSUFFICIENT_CREDITS 402 The workspace’s SMS balance is below the message cost.
NO_WORKSPACE 409 The organization has no active workspace to send from.
NOT_FOUND 404 Message (status lookup) not found.
INTERNAL_ERROR 500 An unexpected server error.

See also