Skip to main content
POST
/
v1
/
businesses
/
{businessId}
/
send
/
messages
Send Session Messages
curl --request POST \
  --url https://api.example.com/v1/businesses/{businessId}/send/messages
Session messages are free-form messages — no pre-approval required. You can send text, attachments, location pins, and interactive messages (list menus, reply buttons). The only constraint is WhatsApp’s 24-hour eligibility window.

The 24-hour rule

You can only send a session message if the recipient has messaged your business within the last 24 hours. If the window has closed, use Send template message to re-engage them instead.
SituationEndpoint to use
Customer messaged you within 24 hoursPOST …/send/messages (this endpoint)
No message from customer in over 24 hoursPOST …/send/whatsapp_templated_messages
First-ever contact with a customerPOST …/send/whatsapp_templated_messages

Endpoint

POST https://api.connectly.ai/v1/businesses/{businessId}/send/messages
Rate limit: 200 requests/second. Exceeding this returns 429 Too Many Requests.

Request body

FieldTypeRequiredDescription
recipientobjectYesThe customer to send to.
recipient.idstringYesCustomer’s WhatsApp number in E.164 format (e.g. +16044441111), or bare BSUID.
recipient.channelTypestringYesSet to whatsapp.
recipient.namestringNoCustomer’s display name.
messageobjectYesThe message content. Provide exactly one content type: text, attachments, location, listMessage, replyButtonMessage, singleProductMessage, or multiProductMessage.
message.idstringNoOptional message identifier (e.g. 01FPW47QF69Y5JZH24605VAKQB).
message.textstringNoPlain text body. Required when sending multiProductMessage; optional for singleProductMessage; standalone text for all other messages.
message.attachmentsarrayNoUp to one attachment per message. Each item has type (image, video, audio, document), url (public URL), optional caption, and optional filename (document only).
message.locationobjectNoA location pin. Fields: latitude, longitude, name, address.
message.listMessageobjectNoAn interactive list message with sections and selectable rows. See WhatsApp docs.
message.replyButtonMessageobjectNoAn interactive message with up to 3 quick-reply buttons. See WhatsApp docs.
message.singleProductMessageobjectNoSend a single product from your Meta catalog. Fields: footer.text, catalogId, productItem.productRetailerId. See WhatsApp docs.
message.multiProductMessageobjectNoSend multiple catalog products grouped into sections. Fields: header, footer, catalogId, sections[].title, sections[].productItems[].productRetailerId. See WhatsApp docs.
message.referralobjectNoRead-only. Populated on inbound messages triggered by a Click-to-WhatsApp ad. Fields: sourceUrl, sourceId, sourceType, headline, body, mediaType, imageUrl, videoUrl, thumbnailUrl, ctwaClid. See WhatsApp docs.
message.isEchobooleanNoSet to true if the message was sent from the business itself.
senderobjectNoSpecifies which of your WhatsApp numbers to send from. Omit if you only have one number.
sender.idstringNoYour WhatsApp sender number in E.164 format (e.g. +14151111234).
sender.channelTypestringNoSet to whatsapp.
sender.namestringNoDisplay name for the sender.
callbackDataanyNoUp to 1024 bytes of JSON echoed back in webhook events for this message. See callbackData.
campaignNamestringNoTags this message with a campaign name for analytics (e.g. test_campaign_2022-03-12).
orderobjectNoOptional config to control event dispatching order.
order.parentIdstringNoID of the parent message this event depends on.
order.strategystringNoDispatch strategy. One of independent or short_circuit. Defaults to strategy_unspecified.

Response

{ "id": "01ARZ3NDEKTSV4RRFFQ69G5FAV" }
The id uniquely identifies the message. Use it to correlate delivery status webhook events.

callbackData

Set callbackData to any JSON value up to 1024 bytes. Connectly echoes it back in every webhook event tied to this message:
  • Delivery status events — sent, delivered, read, delivery_failed
  • Inbound replies that reference this message — quoted replies, button & list replies, reactions
Plain-text replies that don’t quote the original message do not include callbackData. Exceeding 1024 bytes returns a 400 error.
{
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": { "text": "Your order is on its way!" },
  "callbackData": { "order_id": "12345" }
}

Examples

curl --request POST \
  --url https://api.connectly.ai/v1/businesses/<business_id>/send/messages \
  --header 'Content-Type: application/json' \
  --header 'X-API-Key: <YOUR_KEY_HERE>' \
  --data '{
    "sender": { "id": "+14151111234", "channelType": "whatsapp" },
    "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
    "message": { "text": "Hello, how can we help you today?" }
  }'
{
  "sender": { "id": "+14151111234", "channelType": "whatsapp" },
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": {
    "attachments": [
      { "type": "image", "url": "https://example.com/image.jpg", "caption": "Check this out!" }
    ]
  }
}
{
  "sender": { "id": "+14151111234", "channelType": "whatsapp" },
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": {
    "attachments": [
      { "type": "video", "url": "https://example.com/video.mp4", "caption": "Watch this!" }
    ]
  }
}
{
  "sender": { "id": "+14151111234", "channelType": "whatsapp" },
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": {
    "attachments": [
      { "type": "audio", "url": "https://example.com/audio.mp3" }
    ]
  }
}
{
  "sender": { "id": "+14151111234", "channelType": "whatsapp" },
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": {
    "attachments": [
      {
        "type": "document",
        "url": "https://example.com/invoice.pdf",
        "caption": "Your invoice",
        "filename": "invoice.pdf"
      }
    ]
  }
}
{
  "sender": { "id": "+14151111234", "channelType": "whatsapp" },
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": {
    "location": {
      "latitude": 37.7749,
      "longitude": -122.4194,
      "name": "Connectly HQ",
      "address": "123 Main St, San Francisco"
    }
  }
}
Use listMessage to present a scrollable menu. See WhatsApp interactive list docs for full spec.
{
  "sender": { "id": "+14151111234", "channelType": "whatsapp" },
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": {
    "listMessage": {
      "header": { "text": "How can we help?" },
      "footer": { "text": "Choose an option below." },
      "button": { "text": "Select" },
      "sections": [
        {
          "title": "Support",
          "rows": [
            { "id": "1", "text": "Track my order", "description": "Get your order status" },
            { "id": "2", "text": "Returns & refunds", "description": "Start a return" }
          ]
        },
        {
          "title": "Sales",
          "rows": [
            { "id": "3", "text": "Talk to sales", "description": "Speak with our team" }
          ]
        }
      ]
    }
  }
}
You can also use a media header instead of text. Both list and reply-button messages share the same header structure:
"header": {
  "attachment": {
    "type": "image",
    "url": "https://cdn.connectly.ai/your-image.png"
  }
}
For a document header with a filename:
"header": {
  "attachment": {
    "type": "document",
    "url": "https://example.com/menu.pdf",
    "filename": "menu.pdf"
  }
}
Use replyButtonMessage for up to three quick-reply buttons. See WhatsApp reply button docs for full spec.
{
  "sender": { "id": "+14151111234", "channelType": "whatsapp" },
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": {
    "text": "Would you like to confirm your appointment?",
    "replyButtonMessage": {
      "header": { "text": "Appointment reminder" },
      "footer": { "text": "Tap a button to respond." },
      "buttons": [
        { "id": "confirm", "text": "Confirm ✓" },
        { "id": "reschedule", "text": "Reschedule" },
        { "id": "cancel", "text": "Cancel" }
      ]
    }
  }
}
Include the sender object when your business has more than one WhatsApp number.
{
  "sender": { "id": "+14151111234", "channelType": "whatsapp" },
  "recipient": { "id": "+16044441111", "channelType": "whatsapp" },
  "message": { "text": "Hello from our support line!" }
}

Targeting by BSUID

To target a customer identified by a Business-Scoped User ID, set recipient.userId to the bare BSUID (e.g. US.13491208655302741918). See Business-scoped user IDs (BSUID) for full details.
Sending to phone-less (BSUID-only) customers is not yet available and currently returns a 400 error.

Error responses

StatusMeaning
400Malformed body, session window expired, or callbackData exceeds 1024 bytes.
401Missing or invalid X-API-Key.
429Rate limit exceeded (200 req/s).
500Internal server error.
See Error codes for the full list of error types and codes, including ERROR_CODE_MESSAGE_OUTSIDE_OF_ELIGIBILITY_WINDOW.