SMS
Arsel delivers SMS to Saudi Arabia and Egypt. As with email, there are two paths: POST /sms/send for transactional messages to explicit numbers, and campaigns for sends to an audience defined by lists and tags.
Before your first send: register a sender name
The from field is not a phone number — it is an alphanumeric sender name, 3–11 characters, which must be registered and approved in the Arsel Dashboard under Settings > SMS Senders.
This is a regulatory requirement in both KSA and Egypt, not an Arsel policy, and approval goes through the local telecom operators. Messages sent from an unregistered name are rejected outright. Register early — approval is not instant.
Sender names are approved per country. A name cleared for KSA is not automatically usable for Egypt.
Phone number format
| Country | Format | Example |
|---|---|---|
| Saudi Arabia | +9665XXXXXXXX | +966512345678 |
| Egypt | +201XXXXXXXXX | +201012345678 |
Every recipient in a single POST /sms/send call must be in the same country. Mixing KSA and Egypt numbers in one request is rejected. Split them into separate calls.
The cap is 100 recipients per request.
Encoding and message parts
This is the part that surprises people, because it changes what you are billed.
| Encoding | Triggered by | Single message | Per part when split |
|---|---|---|---|
| GSM | Latin letters, digits, common punctuation | 160 characters | 153 characters |
| Unicode | Arabic script, CJK, emoji, unusual symbols | 70 characters | 67 characters |
Encoding is detected automatically from the content, and it is all-or-nothing: one Arabic character or emoji anywhere in the message switches the entire message to Unicode and cuts your budget from 160 characters to 70.
Two consequences worth designing around:
- An Arabic message is billed in 70-character parts throughout. Budget accordingly rather than assuming 160.
- A predominantly-English message with a single decorative emoji costs more than twice what the same message costs without it. If parts matter to you, drop the emoji.
{{variable}} substitution happens before the split, so a long merged value can push a message into an extra part. Test with realistic data, not with {{first_name}} unexpanded.
A message may run to at most 10 parts — 1,530 GSM characters, or 670 Unicode ones. Beyond that the send is rejected with 400 bad_request.
Sending a transactional SMS
curl -X POST "https://api.arsel.sa/v1/sms/send" \
-H "Authorization: Bearer be_your_api_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: otp-user-8821-attempt-1" \
-d '{
"from": "MyApp",
"to": ["+966512345678"],
"content": "Your verification code is {{code}}",
"variables": { "code": "482913" },
"category": "otp"
}'
202 means queued. Poll GET /sms/:id for per-recipient delivery status, which arrives asynchronously from the operator.
OTP flows are exactly where idempotency earns its keep — a retried verification request that sends a second code invalidates the first one from the user's point of view.
Campaigns
The lifecycle mirrors email: create a draft, attach list_ids and tag_ids, then send or schedule. Content supports {{variables}} resolved from contact properties, so the encoding and parts arithmetic above applies per recipient.
Delivery status
SMS delivery receipts come back from the operator and can lag the send by seconds to minutes. A message that shows as queued or sent has not necessarily failed — it may simply not have been reported on yet.
An "undelivered" marketing message frequently means the recipient has registered a do-not-disturb preference with their operator rather than that anything went wrong on your side. Transactional traffic is unaffected by DND.
Reference
| Send SMS · List · Get | Transactional endpoints |
| Campaigns | Create, update, send, cancel, delete |