Send a message

Sends a message to one or more recipients using a template. Supports multi-channel broadcast — when multiple channels are specified (e.g. ["sms", "whatsapp"]), a separate message is created for each (recipient, channel) pair. To choose which of your own numbers a send goes out from, use 'channels': {"sms": [{"from": ["+12125550000", "+14155550000"]}]}. Each channel holds a list of entries, each with 'from' and optionally 'country' and 'strategy'; 'country' and 'strategy' are stored but not acted on yet, so every entry's numbers apply to every recipient on that channel. Every number listed must be an active sender on your account. Like the other account-level preconditions below, that is checked per message rather than when the request is received: the request is still accepted with 202, and each affected message is reported as BLOCKED with error code BUSINESS_029 on GET /messages/{id} and the message.blocked webhook. Each channel's numbers restrict which numbers that channel may use; it does not choose channels — 'channel' does, and the two can be combined. With 'channel' left at auto-detect, a recipient best served by a channel you listed no numbers for still goes out on it. Where several of the listed numbers could serve a recipient, routing prefers the one whose area code matches theirs. Keys: sms, whatsapp, rcs, mms. Returns immediately with per-recipient message IDs for async tracking via webhooks or the GET /messages/{id} endpoint. Sends gated before any delivery attempt do not reject the request — an account-level precondition such as insufficient balance, a template not approved for sending, or free-form content with no open conversation with the contact. The send is accepted with 202 and the affected messages are reported as BLOCKED on GET /messages/{id} and the message.blocked webhook. To send later, set scheduled_at (ISO-8601 with an explicit UTC offset; a value without one is rejected) between 1 minute and 30 days ahead: the response is a ScheduledSendMessageResponse (the same fields plus scheduled_at; status is still QUEUED), each message then moves to SCHEDULED, is held and released at that time (within a few minutes), and a message.scheduled webhook fires once it is held. Balance and template approval are evaluated at release, not at acceptance. Quiet hours are not checked when the request is accepted: if the time falls inside a legally protected quiet-hours window for a recipient, that message is moved to the next allowed time at release and a second message.scheduled webhook reports the new scheduled_at. An account may hold at most 1,000,000 scheduled messages at once (429 LIMIT_001).

POST
/v3/messages

Request Body

application/json

TypeScript Definitions

Use the request body type in TypeScript.

Response Body

application/json

application/json

application/json

application/json

application/json

curl -X POST "https://example.com/v3/messages" \  -H "Idempotency-Key: req_abc123_retry1" \  -H "Content-Type: application/json" \  -d '{    "to": [      "+14155551234",      "+14155555678"    ],    "channel": [      "sms",      "whatsapp"    ],    "channels": null,    "template": {      "id": "7ba7b820-9dad-11d1-80b4-00c04fd430c8",      "name": "order_confirmation",      "parameters": {        "name": "John Doe",        "order_id": "12345"      }    },    "text": null,    "media_urls": null,    "subject": null,    "scheduled_at": null,    "sandbox": false  }'
{
  "success": true,
  "data": {
    "status": "QUEUED",
    "template_id": "7ba7b820-9dad-11d1-80b4-00c04fd430c8",
    "template_name": "order_confirmation",
    "recipients": [
      {
        "message_id": "8ba7b830-9dad-11d1-80b4-00c04fd430c8",
        "to": "+14155551234",
        "channel": "sms",
        "body": "Hi John Doe, your order #12345 has been confirmed."
      },
      {
        "message_id": "8ba7b831-9dad-11d1-80b4-00c04fd430c8",
        "to": "+14155551234",
        "channel": "whatsapp",
        "body": "Hi John Doe, your order #12345 has been confirmed."
      },
      {
        "message_id": "9ba7b840-9dad-11d1-80b4-00c04fd430c8",
        "to": "+14155555678",
        "channel": "sms",
        "body": "Hi John Doe, your order #12345 has been confirmed."
      },
      {
        "message_id": "9ba7b841-9dad-11d1-80b4-00c04fd430c8",
        "to": "+14155555678",
        "channel": "whatsapp",
        "body": "Hi John Doe, your order #12345 has been confirmed."
      }
    ]
  },
  "error": null,
  "meta": {
    "request_id": "req_7X9zKp2jDw",
    "timestamp": "2026-10-20T13:42:48.7554143+00:00",
    "version": "v3"
  }
}
{
  "success": false,
  "data": null,
  "error": {
    "code": "VALIDATION_004",
    "message": "Request validation failed",
    "details": {
      "to": [
        "'to' must contain at least one recipient"
      ],
      "template": [
        "'template' is required"
      ]
    },
    "doc_url": "https://docs.sent.dm/reference/api/error-catalog"
  },
  "meta": {
    "request_id": "req_7X9zKp2jDw",
    "timestamp": "2026-10-20T13:42:48.7554238+00:00",
    "version": "v3"
  }
}
Empty
Empty
{
  "success": false,
  "data": null,
  "error": {
    "code": "RESOURCE_002",
    "message": "Template not found",
    "details": null,
    "doc_url": "https://docs.sent.dm/reference/api/error-catalog"
  },
  "meta": {
    "request_id": "req_7X9zKp2jDw",
    "timestamp": "2026-10-20T13:42:48.7554244+00:00",
    "version": "v3"
  }
}
{
  "success": false,
  "data": null,
  "error": {
    "code": "LIMIT_001",
    "message": "Too many outstanding scheduled messages",
    "details": null,
    "doc_url": "https://docs.sent.dm/reference/api/error-catalog"
  },
  "meta": {
    "request_id": "req_7X9zKp2jDw",
    "timestamp": "2026-10-20T13:42:48.7554247+00:00",
    "version": "v3"
  }
}
{
  "success": false,
  "data": null,
  "error": {
    "code": "INTERNAL_001",
    "message": "Failed to queue message for processing.",
    "details": null,
    "doc_url": "https://docs.sent.dm/reference/api/error-catalog"
  },
  "meta": {
    "request_id": "req_7X9zKp2jDw",
    "timestamp": "2026-10-20T13:42:48.7554266+00:00",
    "version": "v3"
  }
}