---
title: "Send a message"
method: POST
path: "/api/v1/messages"
tags: ["messages"]
---

# Send a message

`POST /api/v1/messages`

Sends a message from one of your Dial numbers.

**The channel is determined by the number, not the request.** A standard
number sends SMS/MMS. An iMessage number sends iMessage, automatically
falling back to RCS/SMS when the recipient can't receive iMessage — you
don't (and can't) pick the channel per message. For standard numbers,
`status` tracks delivery (`sent` → `delivered`/`undelivered`/`failed`,
with a `statusError` reason on failure); iMessage sends report
`status: "unknown"`.

**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).

`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`.

**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.

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`.

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.

## Headers

- `Authorization` string, required

## Request body

- object
  - `to` string, required — Recipient phone number in E.164 format.
  - `fromNumber` string — 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`. Provide exactly one of `fromNumber` or `fromNumberId`.
  - `fromNumberId` string — ID of the Dial number to send from (see List phone numbers). Legacy alternative to `fromNumber` — provide exactly one of the two.
  - `body` string — Message text. Optional when media is attached; a request with neither a non-empty body nor media is rejected with `400`.
  - `forceAudioFile` boolean — Send an audio attachment as a regular file attachment instead of an iMessage voice message. No effect on standard numbers or non-audio media.
  - `mediaUrls` string[] — 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 `201`

Message queued.

- MessagesSendMessageResponse201
  - `message` Message
    - `id` string
    - `phoneNumberId` string
    - `from` string — Sender in E.164 format.
    - `to` string — Recipient in E.164 format.
    - `body` string
    - `direction` 'inbound' | 'outbound'
    - `channel` 'sms' | 'imessage' | 'rcs' | 'unknown' — The channel the message was delivered on. `sms` for SMS/call numbers. For iMessage numbers, inbound messages report the channel actually used — `imessage`, `rcs`, or `sms`. Outbound iMessage sends report `unknown`, because the iMessage channel does not confirm which channel was ultimately used.
    - `service` 'imessage' | 'rcs' | 'sms' — For iMessage numbers, the confirmed delivery channel. Null for SMS/call numbers (where `channel` already says `sms`). Deprecated — prefer `channel`, which is authoritative.
    - `status` 'sent' | 'delivered' | 'undelivered' | 'failed' | 'unknown' | 'received' — Delivery status. Outbound SMS/call messages start at `sent` and reach a terminal `delivered`, `undelivered`, or `failed`. Outbound iMessage messages are `unknown` (the iMessage channel does not report delivery). Inbound messages are `received`.
    - `statusError` string, nullable — A human-readable reason, present only when `status` is `undelivered` or `failed` (for example, when a carrier rejects the message). Null otherwise.
    - `media` MessageMedia[] — Media attachments on the message, in send order. Empty for plain text messages.
      - `id` string — Public media ID — an unguessable 32-character token.
      - `url` string, uri — Stable public URL serving the media (see Get public media). Safe to use directly as an image source; requires no authentication.
      - `contentType` string — MIME type of the media.
      - `originalUrl` string, nullable — The caller-supplied source URL on outbound messages. Null on inbound messages and when the media was uploaded directly as bytes — inbound media is always served from `url`.
    - `replyToId` string, nullable — ID of the message this one replies or reacts to. Set on messages created via Reply to a message, and on inbound threaded replies and reactions received on iMessage numbers. Null for ordinary messages, or when the target of an inbound reply isn't a message on your account.
    - `reaction` string, nullable — The reaction this message carries — a reaction name (`love`, `like`, `dislike`, `laugh`, `emphasize`, `question`) or an emoji — when the message is a reaction, sent or received. Null otherwise. A reaction delivered natively has an empty `body`; a reaction delivered as a regular message over SMS carries the emoji in `body` too.
    - `createdAt` string, date-time

## Other responses

- `400` — The request body failed validation.
- `401` — Missing or invalid API key.
- `402` — Insufficient Dial credit. The number is pay-as-you-go and the account's credit balance is at or below zero. Add credit or start a subscription. (error code `insufficient_credit`.)
- `404` — The requested resource was not found on this account.
- `413` — Request body too large — the media exceeds the 10-item / 5 MB-per-file limits.
- `429` — The recipient is rate-limited. New contacts on iMessage numbers can only receive a limited number of messages until they reply; once they respond, the limit lifts. (error code `rate_limited`.)

---

[API](https://skmtc.net/getdial/apis/rest-api.md) · [All operations](https://skmtc.net/getdial/apis/rest-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/getdial/rest-api/versions/cfa621230237/schema)
