Skip to navigation

Send a message

View as Markdown

Sends a message from one of your Dial numbers.

The number determines the channel, except on a line that carries two. A standard number sends SMS/MMS. An iMessage number sends iMessage, automatically falling back to RCS/SMS when the recipient can’t receive iMessage. A line with WhatsApp connected carries both rails on one number, and that is the one case where you say which you mean — see channel below. For standard numbers, status tracks delivery (sent → delivered/undelivered/failed, with a statusError reason on failure); iMessage sends report status: "unknown".

Destination. Provide exactly one of to (a phone number) or groupId (a group conversation). Sending both — or neither — is rejected with 400 (“Provide exactly one of to or groupId.”). A groupId that isn’t on your account is 400 (“No such group on this account.”), and a group paired with a channel it isn’t on is 400 (“This group is on a different channel than the one you named.”) — leave channel out and the group supplies it. See Group conversations for what a group send does differently.

Media. Attach media as public URLs (mediaUrls, JSON or multipart) or as uploaded media file parts (multipart only):

  • Standard numbers: up to 10 items combined, 5 MB each.
  • iMessage numbers: at most one attachment (URL or file).
  • WhatsApp numbers: at most one attachment (URL or file); a body may accompany it only when the attachment is an image or video.

body is optional when media is attached — a media-only message sends just the attachment (its body is recorded as an empty string). A request with neither a non-empty body nor media is rejected with 400.

Content size (standard numbers). A standard-number message is validated against the carrier’s content-size limits before it is sent, and one that exceeds them is rejected with 400 (“Content size exceeds carrier limit.”) rather than sent.

The body limit depends on the characters used. Plain text allows 1530 characters, but a single character outside the basic SMS alphabet — an em dash, a curly quote, an emoji, any non-Latin script — switches the whole message to a wider encoding and lowers the limit to 670 characters. Attached media may total at most 5 MB.

Even within these limits an individual carrier may still refuse an oversized message at delivery — that surfaces as a failed status with the same statusError reason.

Voice messages (iMessage numbers). When the attachment is a single audio file, it is delivered as a native voice message. If a body is also present, the recipient receives two messages — the text, then the voice message — but the API still returns (and records) a single Message. If the recipient can’t receive voice messages (no iMessage/RCS), the audio is delivered as a link over SMS instead. Set forceAudioFile: true to always send audio as a regular file attachment in one message. forceAudioFile has no effect on standard numbers, non-audio media, or multi-attachment sends — audio attached to a standard number’s message is always MMS media.

Polls (iMessage numbers). Send a poll instead of text by giving poll — a title (1–300 characters) and 2 to 10 options, each non-empty and unique. poll is JSON-only and is exclusive with body, media, and forceAudioFile (400, “Provide either poll or body/media, not both.”). Polls are supported only from iMessage numbers, one-to-one or into an iMessage groupId; a standard number, a WhatsApp send, or a WhatsApp group is rejected with 400 (“Polls are only supported on iMessage numbers.”). Polls have no RCS/SMS rendering, so a recipient without iMessage is rejected with 400 (“This recipient can’t receive polls — polls need iMessage.”). The created message’s body is the title and its poll.options carry the Dial-issued option ids; votes arrive as message.received events (see pollVote) and the message’s poll.options[].votes is the current tally. A poll cannot be replied to, reacted to, or unsent.

Supported types: images (jpeg, png, gif, webp, bmp), audio (mp3, m4a, ogg, wav, amr), video (mp4, 3gpp), pdf, vCard, and iCalendar; any other type is rejected with 400 (HEIC and SVG are not supported). Dial mirrors every attachment into its own storage and serves it from a stable public URL (see Get public media); the message’s media array carries those URLs. For standard numbers, true MMS delivery is supported only for US and Canada — to other destinations the carrier delivers an SMS with a link to the media.

Destination limits (standard numbers): accounts on a subscription can send only to US numbers — any other destination is rejected with 400. Pay-as-you-go accounts can send to any supported destination (a destination with no SMS price tier is rejected with 400).

Choosing the from-number. Provide exactly one of fromNumber (a flexible reference: phone-number ID, one of your numbers in E.164 format, or a nickname) or the legacy fromNumberId (ID only). Sending both — or neither — is rejected with 400.

On a groupId send the from-number is optional, because the group already belongs to one of your lines and Dial sends from that one. Supplying one anyway is allowed and must agree: a from-number naming a different line is rejected with 400 rather than silently overridden.

WhatsApp (channel: "whatsapp"). Sends text and a single media attachment. More than one attachment (across media and mediaUrls) is rejected with 400. A body may accompany media only when the attachment is an image or video — a body alongside audio or a document is rejected with 400. A lone audio attachment is delivered as a voice note by default; set forceAudioFile: true to deliver it as a regular audio file instead. Supported attachment types match the rest of this endpoint (images, audio, video, PDF, vCard, iCalendar); a vCard is delivered as a document, not a native contact card. Inbound WhatsApp attachments are unaffected and arrive as normal media. A WhatsApp send returns status: "unknown" (deliveryState: "unconfirmed") and firms up as receipts arrive; unlike SMS, WhatsApp reports reads, so readState/readAt are meaningful. A WhatsApp line sends one message at a time: a second send while the first is in flight is refused rather than queued.

WhatsApp text sends type first. Before a WhatsApp text message goes out, the recipient (or the group) sees “typing…” for about 200-250 ms per character, up to about 30 seconds however long the message is, and then the message arrives, as it would from a person. The request returns once the message is sent, so it takes that much longer: about 7 seconds for a 30-character message. A send with an attachment doesn’t type.

Not idempotent — there is no idempotency key, so retrying a failed request can send a duplicate message. On an ambiguous failure, confirm via List messages before re-sending.

Authentication

AuthorizationBearer

Your Dial API key, sent as Authorization: Bearer sk_live_...

Request

This endpoint expects an object.
tostringOptional

Recipient phone number in E.164 format. Provide exactly one of to or groupId.

groupIdstringOptional

ID of a group conversation on your account (see List groups), instead of a to number. The sending line comes from the group.

channelenumOptional

Which rail to send on, for a line that carries more than one. Omit to use the number’s own default — a standard number sends SMS, an iMessage number sends iMessage — so existing requests need no change.

sms sends a carrier text from a number without iMessage; on a standard number it is the same as omitting channel. whatsapp requires a line whose WhatsApp channel is ready (otherwise 400, “WhatsApp isn’t connected on this number.”). imessage requires an iMessage-capable number; on a standard SMS/call number it is rejected with 400 rather than delivered as an SMS. Redundant on a groupId send, which is always WhatsApp.

Allowed values:
fromNumberstringOptional

The Dial number to send from, referenced flexibly: a phone-number ID, one of your numbers in E.164 format, or a number’s nickname. A nickname shared by more than one of your numbers is rejected with 400. A replaced number’s ID sends from the number that replaced it (see replacedBy); its E.164 no longer works and returns 404. Provide exactly one of fromNumber or fromNumberId.

fromNumberIdstringOptional

ID of the Dial number to send from (see List phone numbers). Legacy alternative to fromNumber — provide exactly one of the two.

bodystringOptional

Message text. Optional when media is attached; a request with neither a non-empty body nor media is rejected with 400.

forceAudioFilebooleanOptionalDefaults to false

Send a lone audio attachment as a regular file attachment instead of a voice message — an iMessage voice message on iMessage numbers, a WhatsApp voice note on WhatsApp numbers. No effect on standard numbers or non-audio media.

pollobjectOptional

Send a poll instead of text (iMessage numbers only). Exclusive with body, mediaUrls, and forceAudioFile. Not accepted on multipart requests.

mediaUrlslist of stringsOptional

Publicly reachable http(s) URLs of media to attach. Dial downloads each one server-side and re-hosts it; the source URL is preserved on the media item as originalUrl. iMessage numbers accept at most one item.

Response

Message queued.
messageobjectOptional

Errors

400
Bad Request Error
401
Unauthorized Error
402
Payment Required Error
403
Forbidden Error
404
Not Found Error
413
Content Too Large Error
429
Too Many Requests Error