Skip to main content
Send a free-form text message, or an interactive message with buttons, to a phone number. If the number is not an existing contact, Xobito auto-creates a minimal contact.
WhatsApp requires an open 24-hour “customer care” window to send free-form text. If the recipient has not messaged your number in the last 24 hours, use POST /messages/template instead.

Endpoint

POST /api/v1/{subdomain}/messages/send
Required ability: messages.send.

Headers

HeaderValue
AuthorizationBearer apitk_...
Content-Typeapplication/json
Acceptapplication/json

Path parameters

subdomain
string
required
Your workspace subdomain.

Body parameters

phone_number
string
required
Recipient’s phone number in E.164 format.
message_body
string
required
Message body. Max 4096 characters.
message_type
string
One of text, interactive, cta_url. Defaults to text.
header
string
Optional header (interactive / cta_url messages). Max 60 characters.
Optional footer. Max 60 characters.
buttons
array
Interactive button array. 1–3 items. Each button is { id: string (max 256), title: string (max 20) }.
button_text
string
For cta_url messages: the button label. Max 20 characters.
button_url
string
For cta_url messages: the URL the button opens.
contact
object
Optional contact payload. Used when auto-creating or updating the contact backing this message. Any of: firstname, lastname, email, country, assigned_id, groups.

Example request

curl -X POST https://dash.xobito.com/api/v1/acme/messages/send \
  -H "Authorization: Bearer apitk_your_token_here" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -d '{
    "phone_number": "+14155551234",
    "message_body": "Hi John, your order is on the way."
  }'

Interactive reply buttons (1–3)

Send a message with tappable reply buttons. When the user taps a button, the id is sent back as an incoming message to your webhook.
cURL
curl -X POST https://dash.xobito.com/api/v1/acme/messages/send \
  -H "Authorization: Bearer apitk_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155551234",
    "header": "Dropit Wallet",
    "message_body": "💰 Current Wallet Balance: *₹100*\n\nWhat would you like to do?",
    "footer": "Powered by Dropit",
    "message_type": "interactive",
    "buttons": [
      { "id": "view_details", "title": "View Details" },
      { "id": "redeem_now", "title": "Redeem Now" },
      { "id": "share_friend", "title": "Share" }
    ]
  }'
Limits:
  • Max 3 buttons per message
  • Button title max 20 chars
  • Button id max 256 chars (returned verbatim on tap)

CTA URL button (1 URL)

Send a message with a single button that opens a URL in the browser.
cURL
curl -X POST https://dash.xobito.com/api/v1/acme/messages/send \
  -H "Authorization: Bearer apitk_your_token_here" \
  -H "Content-Type: application/json" \
  -d '{
    "phone_number": "+14155551234",
    "message_body": "Thank you for choosing Dropit\n\nCurrent Wallet Balance: *₹100*\nTap below to explore.",
    "message_type": "cta_url",
    "button_text": "View Details",
    "button_url": "https://drop-it.co/get-app"
  }'
Limits:
  • Only 1 URL button per message (Meta restriction)
  • button_text max 20 chars
  • button_url must be a valid HTTPS/HTTP URL
Button type limits: Meta allows only ONE action type per free-form message — either 1–3 reply buttons OR 1 CTA URL button. To mix button types (Reply + URL + Call), you need a pre-approved Meta template via POST /messages/template.

Example response

200 OK
{
  "status": "success",
  "message": "Message sent successfully",
  "data": {
    "message_id": "wamid.HBgLMTQxNTU1NTEyMzQVAgARGBI5QUQ1N...",
    "contact_id": 451,
    "phone": "+14155551234",
    "message": "Hi John, your order is on the way.",
    "status": "sent",
    "sent_at": "2026-04-16T12:00:00.000000Z",
    "chat_id": 88,
    "contact_created": false
  }
}
See Data Types → Message send response.

Auto-created contacts

If phone_number does not match an existing contact, Xobito auto-creates one. The firstname defaults to the phone number unless you supply contact.firstname. contact_created: true indicates a new contact was created.

Error responses

StatusWhenExample body
401Missing / invalid token{"status":"error","message":"Invalid API token"}
403Missing ability{"status":"error","message":"Token does not have the required ability: messages.send"}
422Validation{"status":"error","message":"Validation failed","errors":{"message_body":["The message body may not be greater than 4096 characters."]}}
429Rate limit{"message":"Too many requests","retry_after":45}
500Send failure{"status":"error","message":"Failed to send message"}

Polling delivery status

This endpoint returns the initial status (usually sent). To follow delivery progress (delivered, read, failed), poll GET /messages/{messageId}/status with the returned message_id.
Message delivery does not fire outbound webhooks. Polling is the supported way to track status — see Webhooks Overview.