BluetickedDeveloper docs

SMS

Segments, sender identity and opt-out handling for South African numbers.

SMS: getting live

  1. 1
    Confirm your senderSouth African SMS goes out from a registered sender. Check what yours is before the first send: it appears on every message.Check sender settings
  2. 2
    Mind the segments160 GSM-7 characters in a single segment, or 70 if the body contains any Unicode. Once a message spans multiple segments each one carries a header, so the limits drop to 153 and 67: a 320-character GSM-7 body is three segments, not two. One emoji forces the whole message to Unicode. Every segment is billed.Read the concepts
  3. 3
    Send it with a test keyA blu_test_ key simulates delivery end to end, so you can prove the integration before a real number is involved.Send from the console
  4. 4
    Honour opt-outsA STOP reply suppresses the number automatically and later sends to it are refused. Nothing to build, but your reporting should expect it.View opt-outs

Essentials

STOP & opt-outs
A STOP footer is appended to marketing sends (message_type: "marketing"). A transactional send, the default, goes out exactly as written, so send anything promotional as marketing. Inbound STOP replies suppress the recipient across SMS; START resubscribes. Suppressed numbers are skipped on future sends.
Body & templates
SMS takes a free-form body (max 459 characters; a marketing send's STOP footer counts toward it, and a longer body answers 400) or a saved SMS message template via template_id (workspace-owned, with no provider approval step). A WhatsApp template id on an SMS send returns 404.
Marketing window (South Africa)
Marketing SMS is only accepted inside the permitted hours; sends outside the window are rejected with a validation_failed error whose details.code is sms_marketing_window_closed (branch on details.code, not error.code). Transactional SMS (for example OTPs) is unaffected.
Delivery events
Subscribe a webhook to message.sent / delivered / failed. Inbound replies fire message.received carrying the reply text in `body` (plus conversation_id and from). Read it directly, no follow-up call. Polling GET /messages/{id} is for development only. Authorize SMS sends with messages:send or the least-privilege sms:send scope.

SMS API endpoints

POST/api/v1/messagesmessages:sendTry in console

Send an SMS

Send a plain-text SMS to a contact (or create it with to.create: true), from a free-form body or a saved message template.

Body parameters
channelrequiredstring
torequiredobject
bodystring
  • SMS sends take a free-form body (max 459 chars; a marketing send's STOP footer counts toward it) or a saved message template via template_id (workspace-owned, no provider approval).
  • template_id is channel-aware: SMS/email ids come from your saved message templates; a WhatsApp template id on an SMS send returns 404.
  • A STOP footer is appended to marketing sends only (message_type: "marketing"); a transactional send, the default, goes out exactly as written, so send anything promotional as marketing. Inbound STOP replies suppress the recipient.
  • A closed SA marketing-hours window rejects a marketing SMS with error.code: "validation_failed" and details.code: "sms_marketing_window_closed" (branch on details.code, not error.code).
  • Authorize SMS sends with either messages:send or the least-privilege sms:send scope.
curl -X POST "https://app.blueticked.com/api/v1/messages" \
  -H "Authorization: Bearer $BLUETICKED_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: change-me-per-request-0001" \
  -d '{
  "channel": "sms",
  "to": {
    "phone": "+27800000001"
  },
  "body": "Your OTP is 4821. It expires in 10 minutes."
}'
Response
{
  "message_id": "763c4dc3-d46b-4c10-8bd4-3f233a933ea0",
  "conversation_message_id": "5592edf6-d7ae-4198-962e-3e8ebe83bb49",
  "conversation_id": "fa3efd47-67b2-428c-b75f-17d1dd2e9790",
  "status": "queued",
  "contact_id": "ff506e53-e2f0-4d92-884a-dab77d628bad",
  "contact_created": false,
  "request_id": "req_b2e3d610e10f1b07468721ee98f0e1d2"
}