Skip to main content
The conversations API gives the operator application a read and write surface over the conversation store. You can list all conversations with inbox summary counts, retrieve a single conversation’s full message history, and send outbound messages. These are internal operator endpoints — in production you should place them behind an authenticated session.
All /internal/* endpoints are intended for the operator application and should be placed behind an authenticated session in production. Workspace scoping is enforced at the data layer.

GET /internal/conversations

List conversations from the current backing store, including inbox summary counts. Supports cursor-based pagination via limit and offset.
curl "https://api.your-switchbord.example.com/internal/conversations?limit=25&offset=0"
limit
integer
Maximum number of conversations to return. Defaults to 50, capped at 200.
offset
integer
Number of conversations to skip. Defaults to 0. Must be non-negative.
Response:
summary
object
Inbox summary counts across all conversations (same as GET /internal/inbox/summary).
conversations
array
Array of conversation objects for the current page.
{
  "summary": {
    "total": 142,
    "open": 18,
    "unread": 7
  },
  "conversations": [
    {
      "id": "conv_01hx...",
      "contactId": "ctr_01hx...",
      "status": "open",
      "lastMessageAt": "2025-01-15T10:28:00.000Z",
      "messages": [...]
    }
  ]
}
StatusCondition
200Conversations listed successfully

GET /internal/conversations/

Retrieve a single conversation including its full message history.
curl https://api.your-switchbord.example.com/internal/conversations/conv_01hx...
conversationId
string
required
The conversation identifier returned from the list endpoint.
Response:
conversation
object
The full conversation record with all messages.
{
  "conversation": {
    "id": "conv_01hx...",
    "contactId": "ctr_01hx...",
    "status": "open",
    "lastMessageAt": "2025-01-15T10:28:00.000Z",
    "messages": [
      {
        "id": "msg_01hx...",
        "direction": "inbound",
        "body": "Hello, I need help with my order.",
        "sentAt": "2025-01-15T10:27:00.000Z",
        "status": "delivered"
      },
      {
        "id": "msg_01hx...",
        "direction": "outbound",
        "body": "Hi Jane, happy to help! What's your order number?",
        "sentAt": "2025-01-15T10:28:00.000Z",
        "status": "read"
      }
    ]
  }
}
StatusCondition
200Conversation found
404{"error": "conversation_not_found"}

GET /internal/inbox/summary

Returns inbox summary counts without the full conversation list. Use this for dashboard badge counts.
curl https://api.your-switchbord.example.com/internal/inbox/summary
{
  "total": 142,
  "open": 18,
  "unread": 7
}
StatusCondition
200Summary returned

GET /internal/conversations//messages

Retrieve only the messages for a given conversation without the full conversation metadata.
curl https://api.your-switchbord.example.com/internal/conversations/conv_01hx.../messages
conversationId
string
required
The conversation identifier.
Response:
messages
array
All messages in the conversation, oldest first.
StatusCondition
200Messages returned
404{"error": "conversation_not_found"}

POST /internal/conversations//messages

Send an outbound message in a conversation. Supports freeform text, template sends, interactive messages, and media.
curl -X POST "https://api.your-switchbord.example.com/internal/conversations/conv_01hx.../messages" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "Hi Jane, your order has shipped!",
    "sendMode": "freeform"
  }'
Sending a template:
curl -X POST "https://api.your-switchbord.example.com/internal/conversations/conv_01hx.../messages" \
  -H "Content-Type: application/json" \
  -d '{
    "body": "",
    "sendMode": "template",
    "templateName": "order_shipped_v2"
  }'
conversationId
string
required
The conversation to send the message in.
body
string
required
Message body text. Required and must be at least one character. For template sends, pass an empty string or the template preview text.
sendMode
string
The send mode. One of "freeform" (default), "template", "interactive", or "media".
templateName
string
The approved template name to use. Required when sendMode is "template".
WhatsApp’s 24-hour service window governs when you can send freeform messages. Outside the window, you must use an approved template. Switchbord’s send-eligibility checks enforce this constraint.
Response:
accepted
boolean
true when the message was appended to the conversation.
message
object
The created message record with its assigned ID and status.
{
  "accepted": true,
  "message": {
    "id": "msg_01hx...",
    "direction": "outbound",
    "body": "Hi Jane, your order has shipped!",
    "sendMode": "freeform",
    "sentAt": "2025-01-15T10:30:00.000Z",
    "status": "queued"
  }
}
StatusCondition
201Message accepted and queued
400Validation failure — {"error": "invalid_outbound_message", "issues": {...}}
404Conversation not found — {"error": "conversation_not_found"}