Send SMS Messages with Zavu
Send SMS messages programmatically to any phone number worldwide. REST API, a TypeScript SDK, smart routing across carriers.
SMS (Short Message Service) is the most universal messaging channel, reaching virtually any mobile phone without requiring an internet connection or app installation.
When to Use SMS
- Verification codes: OTPs, 2FA
- Transactional alerts: Order confirmations, shipping updates
- Time-sensitive notifications: Appointment reminders
- Universal reach: When you need to reach users without smartphones
Sending an SMS
const result = await zavu.messages.send({
to: "+14155551234",
text: "Your verification code is 123456",
channel: "sms",
});
Message Length
SMS messages are limited to 160 characters (GSM-7 encoding) or 70 characters (Unicode). Longer messages are split into multiple segments.
| Encoding | Single SMS | Concatenated SMS |
|---|---|---|
| GSM-7 | 160 chars | 153 chars/segment |
| Unicode | 70 chars | 67 chars/segment |
Character Encoding
GSM-7 supports basic Latin characters. Using emojis, accents, or non-Latin scripts triggers Unicode encoding:
CodeGSM-7: "Your code is 123456" (20 chars, 1 segment) Unicode: "Your code is 123456" (22 chars, 1 segment with special chars) Unicode: "Tu codigo es 123456" (19 chars, 1 segment, 'o' with accent triggers Unicode)
GSM-7 Character Set
CodeA-Z a-z 0-9 @ $ _ ! " # % & ' ( ) * + , - . / : ; < = > ? Space, newline, carriage return
Any character outside this set triggers Unicode encoding.
Sender ID
Some countries support alphanumeric sender IDs (e.g., "ZAVU" instead of a phone number).
Supported Countries
| Region | Alphanumeric Sender ID |
|---|---|
| US/Canada | Not supported (10DLC or short code required) |
| UK | Supported |
| EU | Mostly supported |
| LATAM | Varies by country |
SMS Templates
Send pre-defined templates via SMS by specifying channel: "sms" and messageType: "template":
const result = await zavu.messages.send({
to: "+14155551234",
channel: "sms",
messageType: "template",
content: {
templateId: "tpl_abc123",
templateVariables: {
"1": "John",
"2": "ORD-12345",
},
},
});
If the template has an smsBody, it will be used instead of the default body. Contact variables like {{contact.first_name}} are automatically resolved from the recipient's contact metadata.
Delivery Status
Check message status by ID:
terminalcurl https://api.zavu.dev/v1/messages/msg_abc123 \ -H "Authorization: Bearer zv_live_xxx"
| Status | Description |
|---|---|
queued | Accepted, pending delivery |
sent | Sent to carrier |
delivered | Confirmed delivered |
failed | Delivery failed |
Common Errors
| Error Code | Description | Solution |
|---|---|---|
30003 | Unreachable destination | Invalid number or phone off |
30004 | Message blocked | Content filtered by carrier |
30005 | Unknown destination | Number doesn't exist |
30006 | Landline destination | Cannot send SMS to landlines |
30007 | Carrier violation | Message rejected by carrier |
Compliance
Requirements
- Opt-in consent: Users must explicitly agree to receive SMS
- Opt-out mechanism: Include instructions to unsubscribe (e.g., "Reply STOP to unsubscribe")
- Business identification: Identify your business in the message
- Time restrictions: Avoid sending during quiet hours (typically 9 PM - 9 AM local time)
Content check
Every SMS and one-way SMS with text is read before it is sent. A message the
check refuses is answered right away with 422 and code
sms_compliance_blocked; nothing is sent or charged. One-time codes
(verification codes) always pass.
JSON{ "code": "sms_compliance_blocked", "message": "SMS blocked: The message asks for a payment through a link without identifying the sender.", "details": { "riskScore": 85, "messageType": "marketing", "complianceFailures": [ { "code": "MISSING_SENDER_ID", "severity": "high", "title": "Sender not identified" } ], "requiredFixes": ["Name your business in the message."], "suggestedCompliantVersion": "[YourBrand] Your invoice is ready: https://yourbrand.com/pay/123" } }
Apply requiredFixes, or send suggestedCompliantVersion when there is one,
and send again. If the check itself could not run, message says so; retry in
a few minutes.
Example Compliant Message
Code[YourBrand] Your order #12345 has shipped! Track: https://track.co/abc Reply STOP to unsubscribe
Best Practices
- Keep it short - Aim for under 160 characters
- Identify yourself - Start with your brand name
- Be actionable - Include clear next steps or links
- Respect timing - Send during business hours in the recipient's timezone
- Provide opt-out - Always include unsubscribe instructions for marketing messages