Segments and pricing
SMS is billed per segment, not per message. Understanding how segments are counted is the difference between a predictable bill and an unpleasant surprise.
The two alphabets
An SMS is encoded one of two ways, decided entirely by the characters in it.
| Encoding | Single message | Per segment when split |
|---|---|---|
| GSM-7 (standard) | 160 characters | 153 characters |
| UCS-2 (unicode) | 70 characters | 67 characters |
Concatenated messages lose characters to a header that tells the handset how to reassemble them. That is why 161 characters costs two segments of 153 — not 160 plus 1.
One character can double your bill
The usual culprits, all invisible at a glance:
| Character | Looks like | Actually |
|---|---|---|
’ | An apostrophe ' | Curly quote pasted from a word processor — forces UCS-2 |
— | A hyphen - | Em dash — forces UCS-2 |
… | Three dots | Ellipsis character — forces UCS-2 |
| Emoji | One character | Two UCS-2 units, and forces UCS-2 |
A 100-character message costs 1 segment. Paste one curly apostrophe into it and it costs 2 — the same text, twice the price.
Segments are the unit of billing. One SMS credit is one segment, not one message — so a two-segment message to 500 people costs 1,000 credits. See Wallet.
Characters that are safe
Accented Latin characters common in French and Spanish are in the GSM-7 alphabet and cost nothing extra: é è ù ì ò à ä ö ñ ü Å Ø Æ ß É. Only genuinely non-GSM characters force UCS-2.
Characters that cost two
These are in GSM-7 but take two units each: { } [ ] ~ ^ \ | €. A message of 81 opening braces is 162 units — two segments, despite being 81 characters.
Check before you send
Rather than implementing this yourself, ask. The quote endpoint runs the same code the billing path runs, so it cannot disagree with the charge.
curl -X POST https://api.jkasms.com/api/v1/sms/quote \
-H "Authorization: Bearer $JKASMS_SECRET_KEY" \
-H "X-JKASMS-Org-Id: $JKASMS_ORG_ID" \
-H "Content-Type: application/json" \
-d '{
"message": "Your order is on the way \u2019",
"recipients": ["0241234567"]
}'{
"success": true,
"data": {
"recipients": 1,
"segments_per_message": 2,
"total_segments": 2,
"encoding": "UCS2",
"total_cost": "0.12",
"credits_required": 2,
"sufficient_balance": true
}
}encoding: "UCS2" on a short message is the signal that something non-standard slipped in.
When you are charged
You are charged when an upstream network accepts the message — status SUBMITTED — because that is when we are charged. Not when the handset receives it.
| Final status | Charged? | Why |
|---|---|---|
DELIVERED | Yes | Delivered as intended |
FAILED | Yes | A real delivery attempt was made and paid for — e.g. the handset was off for 48 hours |
REJECTED | No — refunded | The network refused it outright (invalid or blocked number) |
EXPIRED | Yes | Accepted by a network, but no final receipt within 48 hours. Acceptance is the billing moment, and a missing receipt says more about the network's reporting than about the handset. |
Refunds appear in your wallet transactions as a REFUND entry against the original message.