Conversations

A conversation is a stateful thread of messages between one of your agents and one external number. Conversations span both SMS and WhatsApp channels — the platform threads inbound and outbound messages onto the same conversation when they share an agent + remote-number pair.

ConceptWhat it is
conversation_id (conv_*)Stable ID for the thread. Returned on every message.received and message.sent event.
ai_modeWho is currently responding: ai, human, or closed.
WindowFor WhatsApp only: rolling 24-hour limit on free-form outbound. Templates bypass it. See WhatsApp guide.

This guide covers list/get, the AI ↔ human handoff via PATCH /v1/conversations/{id}, and live updates via SSE.

List Conversations

$curl "https://api.voicebip.com/v1/conversations?page_size=20" \
> -H "Authorization: Bearer pk_live_your_key"

Filter by agent_id or channel (sms | whatsapp). Paginate with ?page_token=... returned by the previous response. See Pagination for the cursor format.

Response — 200 OK

1{
2 "conversations": [
3 {
4 "conversation_id": "conv_abc123",
5 "agent_id": "agt_PAEZ_njcfm2kycpjs",
6 "channel": "whatsapp",
7 "from_number": "+2348031234567",
8 "to_number": "+2349012345678",
9 "window_expires_at": "2026-05-16T14:32:01Z",
10 "opt_out": false,
11 "created_at": "2026-05-15T10:15:00Z",
12 "updated_at": "2026-05-15T14:32:01Z",
13 "last_message_at": "2026-05-15T14:32:01Z"
14 }
15 ],
16 "next_page_token": "eyJ..."
17}

window_expires_at is WhatsApp-only — null for SMS conversations. To inspect the current ai_mode for a conversation, fetch it via GET /v1/conversations/{conversation_id} — the list endpoint omits it to keep the listing query cheap.

Get a Single Conversation

Returns full message history (paginated reverse-chronological) and metadata.

$curl "https://api.voicebip.com/v1/conversations/conv_abc123" \
> -H "Authorization: Bearer pk_live_your_key"

The response includes the message thread plus the current ai_mode, created_at, and the WhatsApp window state if applicable.

Hand Off to a Human (AI → Human)

Operator dashboards take over an active AI conversation by PATCHing the mode:

$curl -X PATCH "https://api.voicebip.com/v1/conversations/conv_abc123" \
> -H "Authorization: Bearer pk_live_your_key" \
> -H "Content-Type: application/json" \
> -d '{ "ai_mode": "human" }'
TransitionEffect
ai → humanVoicebip stops dispatching new inbound messages to the agent’s BYOM webhook / hosted AI. Operators reply via POST /v1/messages as usual.
human → aiAI dispatcher resumes — the next inbound message is delivered to the agent.
* → closedTerminal. The next inbound message from this remote number starts a brand-new conversation.

Idempotency. PATCHing the same ai_mode returns the current state with changed: false and does not publish a conversation.mode_changed event — safe to call from a click handler that may double-fire.

Audit trail. Every transition writes a row to conversation_mode_history with actor_user_id, from_mode, to_mode, and timestamp. Operators can see who handed off when.

Live Updates via SSE

Subscribe to message and mode-change events for a single conversation:

1const es = new EventSource(
2 `https://api.voicebip.com/v1/conversations/${conversationId}/stream?token=${apiKey}`
3);
4
5es.onmessage = (frame) => {
6 const event = JSON.parse(frame.data);
7 // event.event_type: message.received | message.delivered | message.read | conversation.mode_changed
8 // event.conversation_id
9 // event.timestamp (ISO 8601)
10 // event.payload — event-specific fields (message_id, direction, text, from_mode, to_mode, etc.)
11};

Browsers can’t set custom headers on EventSource, so authenticate via ?token= (server only accepts the query param on this specific path). For server-side consumers use Authorization: Bearer. Full stream reference: Live Streaming.

Export Conversations (CSV / JSON)

For offline analysis or backup:

$curl "https://api.voicebip.com/v1/agents/agt_PAEZ_njcfm2kycpjs/conversations/export?format=csv" \
> -H "Authorization: Bearer pk_live_your_key" \
> -o conversations.csv

format accepts csv or json. The endpoint streams up to 10,000 most-recent conversations for the agent. For larger exports use the deliveries replay API or contact support.

Closing a Conversation

$curl -X PATCH "https://api.voicebip.com/v1/conversations/conv_abc123" \
> -H "Authorization: Bearer pk_live_your_key" \
> -H "Content-Type: application/json" \
> -d '{ "ai_mode": "closed" }'

closed is terminal. The next inbound message from the same remote number to the same agent will create a fresh conv_* ID.

Webhook Events for Conversations

Conversation activity surfaces through the normal messaging webhook events: message.received, message.delivered, message.read (WhatsApp), message.opt_out, and window.closing. See Webhooks for the full event reference.

The conversation.mode_changed event is an internal subject today — it fires on PATCH /v1/conversations/{id} but is not delivered to your webhook URL. The SSE stream above is the recommended way to subscribe to mode changes.