Send an SMS message
POST/api/v1/sms
curl -X POST 'https://www.unitpost.com/api/v1/sms' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'User-Agent: my-app/1.0' \
-H 'Content-Type: application/json' \
-d '{
"to": "+15551234567",
"body": "Your code is 123456"
}'{
"object": "sms",
"id": "id_123",
"to": "customer@example.com",
"from": "you@yourdomain.com",
"direction": "outbound",
"status": "queued",
"type": "transactional",
"body": "string",
"segments": 0,
"country": "string",
"scheduled_at": "2026-01-01T00:00:00.000Z",
"last_error": "string",
"error": {
"code": "out_of_reach",
"message": "string"
},
"created_at": "2026-01-01T00:00:00.000Z"
}Send a single SMS — now, or at a future time by passing scheduled_at. The recipient must be a valid E.164 number; marketing sends additionally require the recipient's prior express consent on record and honor recipient-local quiet hours (they are deferred to the next allowed window, never dropped). The sender is chosen by the recipient's country — the active number or Sender ID whose reach covers it, exactly as campaigns route — unless you pin one with from (a snum_… id from List SMS numbers, or the number / Sender ID string). Pass an Idempotency-Key header to make retries safe: the same key with the same body replays the original message instead of sending (and billing) twice. Billing is per segment. Read delivery state back with Retrieve an SMS message. Requires the sms:send capability.
Request body6 fields
| Field | Type | Description |
|---|---|---|
torequired | string | Recipient phone number in E.164 format, e.g. `+15551234567`. |
from | string | Optional sender to send from: a number id from `GET /sms/numbers` (`snum_…`), or the E.164 number / Sender ID string itself (e.g. `+18005550100`, `Acme`). Must belong to your workspace, be active, and be able to reach the recipient's country — otherwise `404 not_found`, `403 sender_not_approved`, or `422 sender_cannot_reach`. Omit to route automatically: Unitpost picks the active sender whose reach covers the recipient's country (10DLC before toll-free for US recipients; the matching Sender ID elsewhere), exactly as campaigns do. |
bodyrequired | string | Message text. Billing is per segment (160 GSM-7 chars single-segment, 153 per segment concatenated; 70/67 for Unicode). |
type | enumtransactional | marketing | Marketing sends require the recipient's prior express consent on record and honor recipient-local quiet hours. |
scheduled_at | string | ISO-8601 time to send at. Omit to send immediately. |
create_contact | boolean | Create a contact for this recipient if one doesn't exist yet. Defaults to false. Sends don't modify your contact list. When the recipient is already a contact, the message is attached to them either way. A contact created this way records no consent, so it can't be used for marketing sends. |
Response · 200 fields14 fields
| Field | Type | Description |
|---|---|---|
objectrequired | string | — |
idrequired | string | — |
torequired | string | — |
fromrequired | object | — |
directionrequired | enumoutbound | inbound | — |
statusrequired | enumqueued | scheduled | sending | sent | delivered | failed | suppressed | canceled | received | — |
typerequired | enumtransactional | marketing | — |
bodyrequired | object | — |
segmentsrequired | integer | — |
countryrequired | object | — |
scheduled_atrequired | object | — |
last_errorrequired | object | Legacy free-text error. Prefer `error.code`. |
errorrequired | object | Set on `suppressed` messages: the stable skip reason and its sentence. Null otherwise. |
created_atrequired | string | — |