Continue a conversation on another channel
When a customer who started on SMS asks to switch to their email, or a phone call needs to continue as a web-chat session, you can move the conversation without starting a new one. The conversation keeps its identity — same id, same full message history, same tags and assignees — and only the channel your next reply defaults to changes. You can do this two ways:- From the inbox, with the Continue on another channel control on the conversation header.
- Over the API, with
POST /conversations/{id}/resume-channel.
When to move a thread
The move is for the moment a channel stops fitting the conversation — not for fixing a badly routed inbound. Three workflows come up most:- SMS to email for long-form. A customer texts in with a question that needs a document, a formatted list, or a detailed answer. SMS caps each reply at a few segments; moving the thread to email lets you send the full answer with attachments while the customer keeps one continuous thread.
- Voice to web chat for cobrowse. A caller needs you to walk them through your portal. Continuing onto web chat puts a shareable surface between you and the customer so you can cobrowse or exchange links without staying on the phone.
- RCS to SMS for coverage. A thread started on RCS, but the customer’s handset or carrier drops out of RCS coverage mid-conversation. Moving to SMS keeps the thread deliverable instead of dying on the richer channel.
From the inbox
Open the conversation and click Continue on another channel in the header. Orbit lists channels the contact can actually be reached on, and greyed-out entries tell you why a channel is unavailable instead of failing after you pick it. Two disabled reasons matter in practice:- No identity on file — for example, “no email on file” when you pick Email. The fix is on the contact record, not in this dialog: open the contact, add the missing email address or phone number, then reopen the control. Web chat resolves identity down a chain — the visitor’s widget session id first, then their email, then their phone — so a greyed-out Web Chat means the contact has none of the three.
- Already on this channel — the conversation’s current channel renders greyed out as a no-op guard. If you intended a real change, you are looking at the wrong target; if the thread somehow ended up on the wrong channel earlier, moving it away and back is still allowed.
Over the API
The response confirms the move:
previous_channel tells you what the thread was on before this call, and channels is the union of every channel the thread has touched — the full history of all of them loads under this one conversation id. Read already_on_channel before treating the response as a change: on a repeat of the move the call succeeds with already_on_channel: true and nothing is modified, so a client that only checks for HTTP 200 cannot tell a real move from a redundant one.
What carries over, and what does not
Continuing a conversation never creates a new thread and never sends a message on its own. Concretely:- The conversation id and full transcript carry over. Every prior message — from every channel the thread has touched — stays in the same conversation and keeps loading in the inbox.
- Tags and assignees carry over. The move never re-routes ownership; whoever held the thread keeps it.
- The AI-agent session carries over. If an AI agent was handling the thread, the response’s
agent_active: trueandagent_idfields come back unchanged: the same agent keeps its session state and everything it already learned about the contact, and it does not re-introduce itself or start from scratch on the new channel. - The default reply channel changes. Your next reply — and the agent’s next reply — goes out on the new channel without re-picking it each time.
- No message is sent by the move itself. Nothing notifies the customer automatically; if a context note helps, send one as a normal reply.
Failure modes and how to handle them
The endpoint fails closed with one 400 and two distinct 422 shapes, plus the idempotent no-op. Error responses carry a stableerror.code you can branch on:
already_on_channel: true(200, no error). You asked to continue on the channel the conversation is already on. Nothing changed. Detect it from the response body and skip any downstream bookkeeping — do not treat it as a move.MISSING_IDENTITY(400). The contact has no usable address for the target channel.error.details.missing_fieldnames exactly what is missing (for exampleemail address, orvisitor session idwhen every web-chat fallback failed). Fix the contact record, then retry.CONVERSATION_TERMINAL(422). Closed, archived, or snoozed threads cannot be continued. Reopen the thread first, then move it.CHANNEL_NOT_REPLYABLE(422). You passedagentorvideoas the target. Those are labels for how a thread is viewed, not how a customer is reached, so they are rejected at validation. Stick to the channel enum above.
Patterns worth adopting
- Pre-flight the move from
GET /contacts/{id}. The contact record carriesphoneandemail; phone-shaped fields serve every phone-family channel (SMS, WhatsApp, RCS, voice, and the rest), while web chat accepts the email, or phone, or an active widget visitor session. Check before you call — if you are about to targetemailand the contact’semailis empty, fill it in first instead of catching the 400. This turns the missing-identity error from a runtime failure into a form-level validation in your own UI. - Resume after voicemail. A caller who left a voicemail often cannot take another call. Move the thread to SMS or email so the follow-up lands on an asynchronous channel the customer actually answers, with the whole call history still attached.
- Restore the original channel when the detour ends. If you moved SMS → email to deliver a document, move back to SMS once it lands. Because a previously used channel stays in
channels[], moving back is a normal move, not a special case — and the AI agent’s next automated reply goes back onto the customer’s preferred channel too.