API Reference
Send SMS
POST /v1/sms — send a transactional SMS using a pre-approved template.
Send a transactional SMS to a phone number in international format.
/v1/sms Request
curl https://api.zevsend.com/v1/sms \
-H "Authorization: Bearer sk_live_..." \
-H "Content-Type: application/json" \
-d '{
"to": "+2348012345678",
"template_id": "tpl_01HXYZ...",
"variables": {
"code": "847291"
}
}'
Body parameters
| Field | Type | Required | Description |
|---|---|---|---|
to | string | yes | Recipient phone in E.164 (+ then country code then number, no spaces or dashes). |
template_id | string | yes | Template public id (tpl_…). Must be an sms template. |
variables | object | sometimes | Values for the template’s declared customer.* variables. |
brand_domain_id | string | no | Pin the send to a specific verified domain (dom_…) for brand variables like {{brand.name}}. |
Phone format
We accept international format only. Examples:
| Country | Format example |
|---|---|
| Nigeria | +2348012345678 |
| Kenya | +254712345678 |
| Ghana | +233241234567 |
| USA | +12025550100 |
Sending without the + and country code returns 400 invalid_phone.
Response
HTTP/1.1 202 Accepted
Content-Type: application/json
{
"id": "sms_01HXYZ...",
"to": "+2348012345678",
"status": "sending",
"sandbox": false,
"created_at": "2025-05-24T12:34:56.789Z"
}
Lifecycle
| State | Meaning |
|---|---|
queued | Persisted but not yet handed off. |
sending | Handed off to the network; awaiting accept. |
sent | Accepted by the network and in transit. |
delivered | Confirmed at the recipient’s handset. |
failed | Rejected at submit or permanent delivery failure (out-of-window, etc.). |
SMS has no bounced or complained state. Permanent failures
land on failed.
Length limits
The rendered body is capped at 1600 characters. Longer
bodies return 400 body_too_long. Two notes:
- Standard GSM-7 messages are 160 characters per segment. Going over 160 splits across segments and is billed per segment.
- Templates with lots of Unicode (emoji, non-Latin scripts) fall back to UCS-2, which drops the per-segment limit to 70 characters.
The dashboard preview shows the rendered length so you can spot accidental segment splits.
Pricing
SMS is priced per template, in your team’s billing currency. Open the template in the dashboard to see the rate. Each template carries a default per-send price plus any per-country overrides: sending to a recipient in a country with an override charges the override rate; everything else uses the default. The customer-facing rate already accounts for the underlying carrier and route, so you only ever read one number.
Credit drains the moment the carrier accepts the send. Carrier rejections never drain credit. See the Pricing guide for the full charge cascade (plan gate, credit check, dispatch, debit).
Errors
| Status | Code | Cause |
|---|---|---|
400 | invalid_phone | to isn’t a valid E.164 number. |
400 | body_too_long | Rendered SMS exceeds 1600 characters. |
400 | template_id_required | template_id was missing. |
404 | template_not_found | No such template on this team. |
409 | wrong_template_channel | The template is for email or WhatsApp. |
422 | missing_variable | A required variable was missing. |
422 | unknown_variable | You passed a variable the template doesn’t declare. |
403 | no_approved_brand_domain | You’re live but no approved domain exists for the team. |
403 | recipient_not_allowed | Sandbox-only: recipient hasn’t been verified on this team. |
503 | no_carrier_available | No enabled carrier serves the destination region right now. |
Sender ID
A sender ID is the label the recipient sees as the “from” on the message. Every send uses one of three:
- Your team-scope sender ID, when you’ve registered one through the dashboard and it’s been approved for the destination country.
- A ZevSend platform default, when your team hasn’t registered a country-matched sender ID yet. This is a pre-approved transactional sender we maintain so new teams can send OTPs and alerts on day one without waiting for their own sender ID to be reviewed.
- A network-provided ID, on routes where the carrier appends one regardless of submission.
The platform default lets you ship immediately. Once you want your own brand in the from field, register a team-scope sender ID under Settings → SMS → Sender IDs in the dashboard. We’ll review and approve it for the countries you select.
Costs and regions
SMS pricing varies by destination country. The dashboard Usage page shows your per-country breakdown. Some regions require local sender ID registration before delivery is allowed — your dashboard shows which sender ID we’ll use per country.
Updated at, Thursday, October 1, 2026