Skip to content
DocsStart free

Messaging Overview

Messaging runs as its own service at messaging.sip.io, a pure HTTP + data plane (no SIP/media), separate from the voice edge but sharing the same account, numbers, and data model. It does two things: receive inbound messages from your providers and send outbound ones.

ChannelStatusNotes
SMSLiveCarrier-neutral (BYOC) via a config-driven HTTP adapter.
MMSLiveMedia is carried on an SMS/WhatsApp message (the media array), not a separate channel.
WhatsAppLiveCloud API; templates + 24-hour session window.
RCSRoadmapModeled (rcs channel, RBM agent address), but no provider adapter yet.

Five tables, all account-scoped:

TableWhat it holds
messaging_channelA sender: channel (sms/whatsapp/rcs), provider (adapter key), address, provider refs, and an optional default_queue_id. UNIQUE(channel, address).
conversationOne thread per (channel_id, contact_address): status (open/assigned/closed/snoozed), assignment, unread, and the WhatsApp window_expires_at.
messagedirection (inbound/outbound), body, media, status, provider_message_id, and the template_id used.
message_templateWhatsApp/RCS templates: name, language, category, body with {{1}} placeholders, approval status.
message_opt_outThe per-account STOP list: (channel, contact_address).

A contact’s whole history lives in one conversation; messages link to it by conversation_id.

Terminal window
curl -X POST https://messaging.sip.io/send \
-H 'x-api-key: sk_…' -H 'content-type: application/json' \
-d '{ "channelId": "ch_…", "to": "+14155550100", "body": "Hi from SIP.IO" }'

POST /send requires the messaging scope. Body: { channelId, to, body | templateName | mediaUrls, templateLang, templateVars }. It:

  • blocks opted-out recipients (403),
  • enforces the WhatsApp 24h window: outside it, a templateName is required, else 422,
  • dispatches through the channel’s adapter and stores an outbound message.

Returns { ok, messageId, conversationId, providerMessageId, status }.

Each channel has a public inbound URL, POST /inbound/{channelId}, that you register with your provider. On an inbound message the service:

  1. normalizes the provider payload through the channel’s adapter,
  2. handles STOP/START opt-out keywords,
  3. upserts the conversation (reopening a closed one, resetting the WhatsApp window),
  4. stores the inbound message.

Provider status callbacks (delivered/read/failed) arrive on the same URL and update the message by provider_message_id.

Message status is one of queued, sent, delivered, read, failed, received.

Providers are pluggable behind a small adapter interface, selected by the channel’s provider field:

  • generic_http: a regional SMS carrier or aggregator defined entirely in the channel’s metadata (the request URL, auth, and field mapping), so no code is needed to add a carrier.
  • WhatsApp Cloud API, for the whatsapp channel.
  • SMPP and RCS/RBM adapters are planned.

A /v1/messages REST surface on the public API, the omnichannel inbox + routing of inbound conversations into the contact center (the model is in place: default_queue_id, assignment), a message.received webhook, WhatsApp template management, inbound signature verification, and the RCS and SMPP adapters.