POST /sms/lines/{line}/scheduled
Schedule a message
| Scope | sms:send |
| Role permission | Phone numbers — line must be one of theirs |
| Cost | THIS SPENDS MONEY — later. |
Why this needs sms:send, not sms:write: a scheduled message is a
send that has not happened yet. It is priced now and charged when it goes
out, so it requires the same money-spending consent a live send does —
otherwise sms:write would be a way to bill the account tomorrow for
something it cannot bill today.
The price is fixed at the moment you schedule. A later rate-card change does not re-price a message you already committed to.
The STOP list is checked at dispatch, not now: a recipient can opt out between scheduling and sending, and clearing them now would let the message reach someone who has since said stop.
Path parameters
| Name | Type | Required | Example | Description |
|---|---|---|---|---|
line | string | yes | 12125550188 | One of your account's numbers. Digits. |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
to | string[] | yes | |
message | string | no | Required unless media is set. |
subject | string | no | |
media | string[] | no | Hosted URLs, not inline file content — a scheduled MMS references files that already exist rather than carrying megabytes that must be stored until the send time. |
sendAt | string (RFC 3339) | yes | When to send it, RFC 3339. Must be in the future — a past time is almost always a timezone bug in the caller, so it is rejected rather than sent immediately. |
{
"to": [
"13475550123"
],
"message": "Reminder: your appointment is tomorrow at 2pm.",
"sendAt": "2026-08-20T14:30:00Z"
}
Responses
201
Queued.
| Field | Type | Description |
|---|---|---|
id | integer | |
line | string | |
recipients | string[] | |
subject | string | |
text | string | |
media | string[] | |
sendAt | string (RFC 3339) | |
price | number | What it will cost, fixed at the moment it was scheduled. A later rate-card change does not re-price a message you already committed to; the charge lands when it goes out. |
currency | USD |
Errors
| Status | Meaning |
|---|---|
400 | invalid_request — a missing or malformed field, an unknown enum value, or an unknown field in the body. Nothing was charged. |
401 | unauthenticated — no credential, or one that is invalid, revoked or expired. The WWW-Authenticate header names the scope the endpoint wanted. |
403 | Two different failures share this status, and the type tells them apart: |
422 | A destination is not on the account's rate card, so it cannot be priced. Nothing was queued. |
500 | internal_error — something failed on our side. For a send, nothing was charged, guaranteed, which is what makes a retry safe. |
See Errors for the full catalog and what to do about each.
Example
curl -X POST 'https://api.account.telebroad.com/api/public/v1/sms/lines/12125550188/scheduled' \
-H "Authorization: Bearer $TB_KEY" \
-H 'Content-Type: application/json' \
-d '{"to":["13475550123"],"message":"Reminder: your appointment is tomorrow at 2pm.","sendAt":"2026-08-20T14:30:00Z"}'