Skip to content
Get Started

Send a message

POST/api/send-message

Send an iMessage, SMS, MMS, or Sendblue App Card to a single recipient. For enabled dedicated and enterprise accounts, omit from_number on ordinary direct sends to preserve an eligible known-contact line or choose an account-owned online line with effective hourly and daily new-contact capacity. An account admin enables Automatic API line selection in the dashboard API settings (Settings > API keys in the Beta Dashboard, or Settings > API Settings in the legacy dashboard). Both dashboards control the same account-wide setting, which defaults off; other accounts keep their existing omitted-sender routing. An eligible saved conversation line stays selected during temporary outages while the contact is still known on that line. Expired offline routes are excluded. Retained replacement lines can only continue contacts known on that same line. Explicit senders remain authoritative. Other sending rules still apply. The accepted response identifies the selected line in from_number and sendblue_number. If all eligible lines reach a new-contact cap, the response is HTTP 400 with status ERROR, body error_code 429, and error_key LINE_HOURLY_LIMIT_REACHED or LINE_DAILY_LIMIT_REACHED. HTTP 429 is reserved for request-rate limiting.

Body ParametersJSONExpand Collapse
number: string

Recipient phone number in E.164 format

app_card: optional object { appName, extensionBundleId, layout, 7 more }

A Sendblue App Card rendered with Apple’s Messages framework. App Cards require a V2 Mac line and an iMessage-capable recipient; they never fall back to SMS. The URL is delivered to the identified Messages extension when the recipient taps the card. An initial App Card may include reply_to to create an inline reply. Later state changes use the update endpoint, which sends a new Apple message in the same App Card session. The feature is unavailable on the free plan.

appName: string
extensionBundleId: string
layout: object { caption, imageSubtitle, imageTitle, 5 more }

Visible card fields mirroring Apple’s MSMessageTemplateLayout.

caption: optional string
imageSubtitle: optional string

Secondary text overlaid on the preview image. Requires imageUrl.

maxLength1024
imageTitle: optional string

Text overlaid on the preview image. Requires imageUrl.

maxLength1024
imageUrl: optional string

HTTPS preview image fetched by the worker and sent as a hidden card attachment. JPEG, PNG, HEIC, HEIF, and WebP are supported up to 10 MB.

formaturi
maxLength2048
subcaption: optional string
summary: optional string

Fallback text used in notifications and non-rendering surfaces.

maxLength1024
trailingCaption: optional string
trailingSubcaption: optional string
teamId: string
url: string

URL delivered to the iMessage extension on tap. HTTPS URLs are limited to 2048 characters; data URLs carrying inline app state are limited to 16384.

formaturi
maxLength16384
appStoreId: optional number

Optional numeric App Store ID for recipients without the extension.

minimum1
fallbackText: optional string

Fallback text for notifications and surfaces that cannot render the card.

maxLength1024
interactive: optional boolean

Use Apple’s live layout when the extension is installed; false always sends the static template layout.

sessionIdentifier: optional string

Optional caller-supplied App Card session UUID. Generated automatically when omitted.

formatuuid
updateMessageHandle: optional string

Original message handle for an App Card continuation returned by the update endpoint.

content: optional string

Message text content. Optional when media_url or app_card is provided.

maxLength18996
from_number: optional string

Your registered Sendblue phone number in E.164 format. Optional on dedicated and enterprise ordinary direct sends; automatic capacity-aware selection requires account enablement. Required on free shared-line plans. Provide a sender for App Cards and inline replies; those requests do not use automatic capacity-aware selection.

media_url: optional string

URL of media file to send (images, videos, etc.)

formaturi
pre_reply_override: optional boolean

Let one otherwise-blocked message through to a contact who has not replied yet, once per contact per line per day. Must be the boolean true.

reply_to: optional object { message_handle, part_index }

Optional inline-reply target. This may be combined with app_card; the resulting App Card is sent as an inline reply to the target.

message_handle: string

Public handle of the immediate parent message

part_index: optional number

Advanced override for a known part of a multipart target. Omit this in normal reply requests and never guess it; requests default to 0. When replying to an attachment represented by its own webhook, use that webhook’s message_handle and omit part_index so Sendblue can use the stored authoritative part. Responses omit it when no authoritative immediate-parent part is available.

minimum0
maximum50
seat_id: optional string

Optional. Identifies the seat (user) sending the message so the message is attributed to a specific rep. Accepts either the seat UUID or the Firebase Auth subject. When provided, sender_email is auto-populated on the message record and webhook payloads. Returns 400 if the seat is not found.

send_style: optional "celebration" or "shooting_star" or "fireworks" or 10 more

The iMessage expressive message style

One of the following:
"celebration"
"shooting_star"
"fireworks"
"lasers"
"love"
"confetti"
"balloons"
"spotlight"
"echo"
"invisible"
"gentle"
"loud"
"slam"
status_callback: optional string

Webhook URL that receives message status updates

formaturi
text_formatting: optional array of object { length, start, styles }

Optional additive native text styles indexed in UTF-16 code units of the exact submitted content. Empty array retains the ordinary plain-text path. Ranges cannot split surrogate pairs. Requires an updated V2 Mac worker/native helper, macOS 15+ and an existing native iMessage path. Other transports, older workers/hosts and AppleScript paths remain plain text; routing and fallback policy do not change. Cannot be combined with app_card. Recipient rendering requires compatible Apple Messages.

length: number
start: number
styles: array of "bold" or "italic" or "underline" or "strikethrough"
One of the following:
"bold"
"italic"
"underline"
"strikethrough"
ReturnsExpand Collapse
MessageResponse object { account_email, app_card, content, 19 more }
account_email: optional string

Email of the account that sent the message

app_card: optional object { appName, extensionBundleId, layout, 7 more } or object { balloonBundleId, extensionBundleId, revision, 3 more }

App Card data sent or received with this message.

One of the following:
AppCard object { appName, extensionBundleId, layout, 7 more }

A Sendblue App Card rendered with Apple’s Messages framework. App Cards require a V2 Mac line and an iMessage-capable recipient; they never fall back to SMS. The URL is delivered to the identified Messages extension when the recipient taps the card. An initial App Card may include reply_to to create an inline reply. Later state changes use the update endpoint, which sends a new Apple message in the same App Card session. The feature is unavailable on the free plan.

appName: string
extensionBundleId: string
layout: object { caption, imageSubtitle, imageTitle, 5 more }

Visible card fields mirroring Apple’s MSMessageTemplateLayout.

caption: optional string
imageSubtitle: optional string

Secondary text overlaid on the preview image. Requires imageUrl.

maxLength1024
imageTitle: optional string

Text overlaid on the preview image. Requires imageUrl.

maxLength1024
imageUrl: optional string

HTTPS preview image fetched by the worker and sent as a hidden card attachment. JPEG, PNG, HEIC, HEIF, and WebP are supported up to 10 MB.

formaturi
maxLength2048
subcaption: optional string
summary: optional string

Fallback text used in notifications and non-rendering surfaces.

maxLength1024
trailingCaption: optional string
trailingSubcaption: optional string
teamId: string
url: string

URL delivered to the iMessage extension on tap. HTTPS URLs are limited to 2048 characters; data URLs carrying inline app state are limited to 16384.

formaturi
maxLength16384
appStoreId: optional number

Optional numeric App Store ID for recipients without the extension.

minimum1
fallbackText: optional string

Fallback text for notifications and surfaces that cannot render the card.

maxLength1024
interactive: optional boolean

Use Apple’s live layout when the extension is installed; false always sends the static template layout.

sessionIdentifier: optional string

Optional caller-supplied App Card session UUID. Generated automatically when omitted.

formatuuid
updateMessageHandle: optional string

Original message handle for an App Card continuation returned by the update endpoint.

InboundAppCard object { balloonBundleId, extensionBundleId, revision, 3 more }

App Card session metadata received from an iMessage contact.

balloonBundleId: string
extensionBundleId: string
revision: number

Retry-stable occurrence revision assigned to this inbound App Card state.

minimum1
sessionIdentifier: string
teamId: string
url: string
content: optional string

Message content

date_created: optional string

When the message was created

formatdate-time
date_updated: optional string

When the message was last updated

formatdate-time
error_code: optional number

Numeric error code if message failed

error_key: optional string

Stable identifier of the rule that declined the message, e.g. PRE_REPLY_LIMIT_REACHED or OPTED_OUT. Branch on this field. null when the message was not declined by a rule.

error_message: optional string

Error message if message failed

from_number: optional string

Sending phone number

is_outbound: optional boolean

Whether this is an outbound message

is_reaction: optional boolean

Present as true only for positively identified inbound reaction additions or removals on supported V2 lines. The handle identifies the reaction event and cannot be an inline-reply target. Absence does not establish replyability.

location: optional object { latitude, longitude, accuracy, 3 more }

Decoded Find My location share coordinates.

latitude: number
longitude: number
accuracy: optional number

Horizontal accuracy in meters

formatdouble
altitude: optional number

Altitude in meters

formatdouble
duration: optional string

Share duration selected by the recipient

timestamp: optional string
media_url: optional string

URL of attached media

message_handle: optional string

Unique identifier for tracking the message

message_type: optional "message" or "group" or "location"
One of the following:
"message"
"group"
"location"
number: optional string

Recipient phone number

reply_to: optional object { message_handle, part_index }

Immediate parent of an iMessage inline reply. The target must belong to the same account, conversation, and sending line.

message_handle: string

Public handle of the immediate parent message

part_index: optional number

Advanced override for a known part of a multipart target. Omit this in normal reply requests and never guess it; requests default to 0. When replying to an attachment represented by its own webhook, use that webhook’s message_handle and omit part_index so Sendblue can use the stored authoritative part. Responses omit it when no authoritative immediate-parent part is available.

minimum0
maximum50
seat_id: optional string

UUID of the seat that sent the message. Present when seat_id was provided on send, or for dashboard-originated group messages.

formatuuid
send_style: optional "celebration" or "shooting_star" or "fireworks" or 10 more

The iMessage expressive message style

One of the following:
"celebration"
"shooting_star"
"fireworks"
"lasers"
"love"
"confetti"
"balloons"
"spotlight"
"echo"
"invisible"
"gentle"
"loud"
"slam"
sender_email: optional string

Email of the seat (user) that sent the message. Auto-populated when a seat_id is provided on send. null for messages sent without a seat_id.

formatemail
status: optional "QUEUED" or "SENT" or "DELIVERED" or "ERROR"
One of the following:
"QUEUED"
"SENT"
"DELIVERED"
"ERROR"
thread_originator: optional object { message_handle, part }

Message that originated an iMessage inline-reply thread.

message_handle: string

Public handle of the thread’s root message

part: optional string

Opaque Apple thread-originator part descriptor

Send a message

curl https://api.sendblue.co/api/send-message \
    -H 'Content-Type: application/json' \
    -H "sb-api-key-id: $SENDBLUE_API_API_KEY" \
    -H "sb-api-secret-key: $SENDBLUE_API_API_SECRET" \
    -d '{
          "number": "+19998887777",
          "content": "Hello, World!",
          "from_number": "+19998887777",
          "media_url": "https://example.com/image.jpg",
          "pre_reply_override": true,
          "seat_id": "550e8400-e29b-41d4-a716-446655440000",
          "send_style": "celebration",
          "status_callback": "https://example.com/webhook"
        }'
{
  "account_email": "user@example.com",
  "app_card": {
    "appName": "My App",
    "extensionBundleId": "com.example.myapp.MessagesExtension",
    "layout": {
      "caption": "Check this out",
      "imageSubtitle": "imageSubtitle",
      "imageTitle": "imageTitle",
      "imageUrl": "https://example.com",
      "subcaption": "Tap to open",
      "summary": "summary",
      "trailingCaption": "trailingCaption",
      "trailingSubcaption": "trailingSubcaption"
    },
    "teamId": "ABCDE12345",
    "url": "https://example.com/deep-link",
    "appStoreId": 1234567890,
    "fallbackText": "fallbackText",
    "interactive": true,
    "sessionIdentifier": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
    "updateMessageHandle": "updateMessageHandle"
  },
  "content": "Hello, World!",
  "date_created": "2023-10-01T12:00:00Z",
  "date_updated": "2023-10-01T12:00:01Z",
  "error_code": 0,
  "error_key": null,
  "error_message": "error_message",
  "from_number": "+19998887777",
  "is_outbound": true,
  "is_reaction": true,
  "location": {
    "latitude": 37.7749,
    "longitude": -122.4194,
    "accuracy": 12,
    "altitude": 8,
    "duration": "oneHour",
    "timestamp": "2026-06-23T12:00:00.000Z"
  },
  "media_url": "https://cdn.sendblue.co/media/abc123.jpg",
  "message_handle": "msg_abc123def456",
  "message_type": "message",
  "number": "+18887776666",
  "reply_to": {
    "message_handle": "msg_parent123",
    "part_index": 0
  },
  "seat_id": "550e8400-e29b-41d4-a716-446655440000",
  "send_style": "celebration",
  "sender_email": "rep@example.com",
  "status": "QUEUED",
  "thread_originator": {
    "message_handle": "msg_root456",
    "part": "0:0"
  }
}
Returns Examples
{
  "account_email": "user@example.com",
  "app_card": {
    "appName": "My App",
    "extensionBundleId": "com.example.myapp.MessagesExtension",
    "layout": {
      "caption": "Check this out",
      "imageSubtitle": "imageSubtitle",
      "imageTitle": "imageTitle",
      "imageUrl": "https://example.com",
      "subcaption": "Tap to open",
      "summary": "summary",
      "trailingCaption": "trailingCaption",
      "trailingSubcaption": "trailingSubcaption"
    },
    "teamId": "ABCDE12345",
    "url": "https://example.com/deep-link",
    "appStoreId": 1234567890,
    "fallbackText": "fallbackText",
    "interactive": true,
    "sessionIdentifier": "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
    "updateMessageHandle": "updateMessageHandle"
  },
  "content": "Hello, World!",
  "date_created": "2023-10-01T12:00:00Z",
  "date_updated": "2023-10-01T12:00:01Z",
  "error_code": 0,
  "error_key": null,
  "error_message": "error_message",
  "from_number": "+19998887777",
  "is_outbound": true,
  "is_reaction": true,
  "location": {
    "latitude": 37.7749,
    "longitude": -122.4194,
    "accuracy": 12,
    "altitude": 8,
    "duration": "oneHour",
    "timestamp": "2026-06-23T12:00:00.000Z"
  },
  "media_url": "https://cdn.sendblue.co/media/abc123.jpg",
  "message_handle": "msg_abc123def456",
  "message_type": "message",
  "number": "+18887776666",
  "reply_to": {
    "message_handle": "msg_parent123",
    "part_index": 0
  },
  "seat_id": "550e8400-e29b-41d4-a716-446655440000",
  "send_style": "celebration",
  "sender_email": "rep@example.com",
  "status": "QUEUED",
  "thread_originator": {
    "message_handle": "msg_root456",
    "part": "0:0"
  }
}