RaabtaHQ
Send a message

Send a message

POST/api/v1/messages

scope messages:sendIdempotent

Send a text, template or media message into an existing conversation, or to a phone number on WhatsApp / personal WhatsApp — the contact and thread are found or created. Text and media outside WhatsApp’s 24-hour customer-service window fail with unprocessable / outside_window; send a template instead. Templates are WhatsApp-only. The message is recorded in the inbox as sent by the assistant/API (sender_type: bot).

Body

application/json
NameTypeDescription
type: "text"optional
object
typerequired
stringtext
torequired
one ofWhere to send
to (option 1)optional
objectAddress an existing thread
to.conversation_idrequired
string (uuid)An existing thread on any channel
to (option 2)optional
objectAddress a phone number; the contact and thread are found or created
to.phonerequired
stringE.164 phone number, e.g. +971501234567
to.channeloptional
string (enum)The phone-keyed channel to send onwhatsapppersonal_whatsappDefault: whatsapp
to.connection_idoptional
string (uuid)Required for personal_whatsapp: the linked number to send from
textrequired
stringMessage text
type: "template"optional
object
typerequired
stringtemplate
torequired
one ofWhere to send
to (option 1)optional
objectAddress an existing thread
to.conversation_idrequired
string (uuid)An existing thread on any channel
to (option 2)optional
objectAddress a phone number; the contact and thread are found or created
to.phonerequired
stringE.164 phone number, e.g. +971501234567
to.channeloptional
string (enum)The phone-keyed channel to send onwhatsapppersonal_whatsappDefault: whatsapp
to.connection_idoptional
string (uuid)Required for personal_whatsapp: the linked number to send from
templaterequired
object
template.namerequired
stringTemplate name, as approved by Meta
template.languageoptional
stringTemplate language codeDefault: en_US
template.body_paramsoptional
string[]Values for {{1}}, {{2}}, … in the body
template.header_textoptional
stringValue for a text header variable
template.header_media_urloptional
string (url)Public URL for an image/video/document header
template.button_paramsoptional
map<string, string>Per-button values keyed by button index, for URL-suffix and copy-code buttons
type: "media"optional
object
typerequired
stringmedia
torequired
one ofWhere to send
to (option 1)optional
objectAddress an existing thread
to.conversation_idrequired
string (uuid)An existing thread on any channel
to (option 2)optional
objectAddress a phone number; the contact and thread are found or created
to.phonerequired
stringE.164 phone number, e.g. +971501234567
to.channeloptional
string (enum)The phone-keyed channel to send onwhatsapppersonal_whatsappDefault: whatsapp
to.connection_idoptional
string (uuid)Required for personal_whatsapp: the linked number to send from
mediarequired
object
media.kindrequired
string (enum)imagevideodocumentaudio
media.urlrequired
string (url)A public URL the channel fetches at send time
media.captionoptional
string
media.filenameoptional
stringShown for documents
Request
curl -X POST "https://your-crm.example.com/api/v1/messages" \
  -H "Authorization: Bearer $RAABTA_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f1c2a9e-3b4d-4c5e-8f7a-9b0c1d2e3f4a" \
  -d '{
    "type": "text",
    "to": {
      "phone": "+971501234567",
      "channel": "whatsapp"
    },
    "text": "Your appointment is confirmed for Saturday at 11:00."
  }'
Response · 201 Created
{
  "data": {
    "id": "0c1d2e3f-4a5b-4c6d-8e7f-8a9b0c1d2e3f",
    "conversation_id": "4e5f6a7b-8c9d-4e0f-a1b2-c3d4e5f6a7b8",
    "direction": "outbound",
    "sender_type": "bot",
    "type": "text",
    "text": "Your appointment is confirmed for Saturday at 11:00.",
    "media_url": null,
    "template_name": null,
    "status": "sent",
    "channel_message_id": "wamid.HBgLOTcxNTAxMjM0NTY3FQIAERgSN0Y4MjA1QzYwRjkzMDAyMzRCAA==",
    "reply_to_message_id": null,
    "created_at": "2026-09-02T10:00:00.000Z"
  }
}

Response

Wrapped in { data: … }
NameTypeDescription
idrequired
string (uuid)UUID
conversation_idrequired
string (uuid)UUID
directionrequired
string (enum)inbound = from the customerinboundoutbound
sender_typerequired
string (enum)bot = the assistant or an API key; agent = a member in the inboxcustomeragentbot
typerequired
string (enum)Content typetextimagedocumentaudiovideolocationtemplateinteractive
textrequired
string | nullBody text, or the caption of a media message
media_urlrequired
string | nullURL of the attached image, video, document or audio
template_namerequired
string | nullThe template this message was sent from, for template sends
statusrequired
string (enum)Delivery status as reported by the channelsendingsentdeliveredreadfailed
channel_message_idrequired
string | nullThe channel’s own id (a WhatsApp wamid, a Messenger mid)
reply_to_message_idrequired
string (uuid) | nullThe message this one replies to, when the customer quoted one
created_atrequired
string (date-time)ISO 8601 timestamp

Errors

StatusCodeWhen
400bad_requestThe request could not be parsed: malformed JSON, an invalid cursor, or a query parameter of the wrong shape.
400validation_errorThe body or query failed validation. `details` lists each failing field with a `path` and a `message`.
401unauthorizedNo usable API key: the Authorization header is missing or malformed, or the key is unknown, revoked or expired. The three are deliberately indistinguishable.
402plan_limit_reachedThe account has reached a plan limit for this resource. `details[0].limit` is the cap; ask the account owner to raise it.
403forbiddenThe key is valid but lacks the scope this endpoint requires, or the request came from an address outside the key’s IP allowlist. The message says which.
403account_suspendedThe account this key belongs to is suspended. Rotating the key will not help; contact support.
404not_foundNo such resource in this account. A resource that exists in another account also returns this.
409conflictThe request conflicts with current state: a duplicate phone number on create, an invalid state transition, or an idempotent request that is still in flight.
422unprocessableThe request was well-formed but cannot be carried out. `reason` is a stable string saying why (for example `outside_window` or `stage_not_in_pipeline`).
422channel_not_connectedThe channel this request needs is not connected on the account. Connect it in Settings and retry.
429rate_limitedThe per-key budget, or the per-IP budget for failed authentication, is exhausted. Honour `Retry-After` before retrying.
500internalSomething failed on our side. Safe to retry with the same Idempotency-Key; quote `request_id` if it persists.