Skip to main content

Side conversations

Some conversations cannot be closed by the operator alone. A finance dispute needs a reference number from the bank. A port-out dispute needs the carrier’s numbering team. A fraud escalation needs a specialist two floors away who does not hold an Orbit seat. Side conversations give the operator a child thread attached to the customer conversation so that external party can be looped in, exchanged with, and closed out — without a single character of that exchange reaching the customer. The customer never sees a side conversation. It does not appear in their portal, it is not merged into the customer-facing thread, and no side-conversation participant ever receives a reply addressed to the customer. The boundary is absolute: the parent conversation continues as though nothing happened, while the operator clears the blocker in parallel. This guide walks through the full lifecycle over the API: spawn a side thread, reply outward and log received answers inward, resolve it, reopen it when the external party comes back, and read the history. For the raw request/response schema, see the Conversations API reference.

What a side conversation is — and where the privacy boundary sits

A side conversation is a child thread under a parent conversation. The parent is the customer-facing thread the operator is working; the child is a private channel between the operator (or the tenant, via automation) and one or more external participants — a person outside your tenant and outside the customer relationship, identified by label and optionally an email, phone number, or role. Three properties define the surface:
  • The child always hangs off a parent conversation. You address every endpoint by the parent’s conversation id plus the side conversation id ({sideId}). A side conversation cannot exist detached from a customer thread, and deleting the parent removes the children with it.
  • The customer is not a participant and cannot become one. Side threads never enter the customer-facing timeline, never roll into the unified inbox as customer-visible turns, and never expose the parent’s contents to the external participant — the participant only sees the turns the operator explicitly writes into the side thread.
  • External participants are declared, not discovered. You attach up to ten participants (each with label and optional email, phone, role) when you spawn the thread. The API enforces no cross-check against your contact book — the label is the record.
Use this boundary deliberately. Anything the external participant must see, the operator writes into the side conversation by hand. Anything the customer must see, the operator writes into the parent thread. Nothing crosses automatically.

Spawning a side conversation

POST /api/v1/conversations/{id}/side-conversations creates the child thread. Two fields are required: a subject (up to 200 characters — it becomes the thread’s title in the dashboard) and the external_participants array (one to ten entries). Each participant carries a required label and an optional email, phone, and role — there is no enforcement that a participant carries a reachable address, the fields are descriptive. An optional initial_message opens the outbound turn in the same call. Use it when the operator already knows the opening question — it saves a round-trip and leaves the thread with a complete first exchange visible to anyone who picks it up.
Send an Idempotency-Key on the spawn: creation is the one place a retried POST would otherwise produce two parallel threads, and the same key replays the original response for 24 hours (see Idempotency for the full header semantics).

Replying: outbound to the external party, inbound to log their answer

POST /api/v1/conversations/{id}/side-conversations/{sideId}/reply appends a message to the side thread. Three fields govern the turn:
  • body (required, up to 10,000 characters) — the message text.
  • direction — outbound (the default) means the operator is typing to the external participant. inbound means the operator is logging an answer the external participant already sent over a side channel (an email, a phone call) so the thread holds the complete record.
  • author_label — an optional override for who the turn is attributed to; use it on inbound turns to name the external participant rather than the operator doing the logging.
The direction distinction is the record-keeping hinge of the whole feature. Orbit does not transmit the turn to the external participant — there is no SMTP send or SMS dispatch hidden in the reply endpoint, so invariant guardrails around customer messaging never see this traffic. The outbound turn is written to the thread; the operator (or your own integration reading the thread) carries the content to the external party. When the party answers — on email, on the phone — the operator logs that answer as an inbound reply so the audit trail shows both halves of the exchange in one place.

Lifecycle: resolve, reopen, and the resolved-state wall

A side conversation has exactly two statuses — open and resolved — and two transitions between them:
  • Resolve — POST /api/v1/conversations/{id}/side-conversations/{sideId}/resolve stamps status='resolved', resolved_at, and resolved_by. Resolve is idempotent in the audit sense: re-resolving an already-resolved thread succeeds and rewrites resolved_at to the current time, so the audit trail reflects the most recent deliberate close rather than an error.
  • Reopen — POST /api/v1/conversations/{id}/side-conversations/{sideId}/reopen flips the status back to open and clears resolved_at and resolved_by. Reopen is the sibling of resolve, so the operator UI can offer one button when status='resolved'.
  • The 422 wall — while status='resolved', POST .../reply is rejected with HTTP 422. The operator interface surfaces this as a prompt to reopen first; your integration should too — catch the 422, call reopen, retry the reply. Do not work around the wall by spawning a second side thread: the resolved thread is the audit record of why the first loop closed.
The reply → 422 → reopen → retry sequence is the intentional control: a resolved loop is ended, and reopening it is a deliberate act that the audit trail records.

Listing and reading

Two read endpoints cover the surface:
  • GET /api/v1/conversations/{id}/side-conversations returns every side conversation attached to the parent, newest first, capped at 200. Two hundred side threads on a single customer conversation is extreme in practice, so the cap is not pagination you will normally meet — when you do, split the parent conversation rather than paging side threads.
  • GET /api/v1/conversations/{id}/side-conversations/{sideId}/messages returns the full message thread for one side conversation, oldest first, capped at 500 messages.
Read the list to render a parent conversation’s side work in your own operator surface; read the thread to export the exchange into a case file.

Operator playbook — three loops that pay for the feature

Finance dispute, bank-reference loop. A customer opens a chargeback dispute. The operator spawns a side conversation with the issuing bank’s disputes desk (label + email), opens with an initial_message containing the dispute id, and leaves the parent thread with a holding reply to the customer. When the bank emails the ARN, the operator logs it as an inbound reply, resolves the side thread, and the parent conversation carries the resolution. Port-out dispute, carrier-SME loop. A customer contests a port rejection. The operator spawns a side thread with the losing carrier’s numbering team so the operator can exchange the LOA details without the customer watching a conversation about a carrier they may no longer be leaving for. The side thread holds the full back-and-forth; resolution closes with the corrected port date. Fraud escalation. A tier-1 operator suspects account takeover and spawns a side thread with your fraud desk as an internal-but-outside participant (label, role — no email needed when the loop is a desk, not a box). The fraud specialist reads only what the operator writes into the side thread. If the suspicion clears, resolve leaves an audit trail; if it turns into action, the parent thread is untouched until the operator chooses to tell the customer.

What side conversations are not

Three adjacent features solve different problems — pick the right one:
  • Team chat is for internal coordination — operators talking to each other about the work. It is not attached to a customer conversation, it has no parent thread, and it does not address an external party. Side conversations are tied to a customer conversation and address someone outside the tenant.
  • Inbox agent scripts are the operator’s canned prompts — pre-vetted text to send into a customer-facing thread. A side conversation is an actual channel with an external participant, not a snippet library.
  • Inbox reply approvals gate what an operator may send to the customer. Side conversations never send anything to the customer at all — the approval chain does not apply, because nothing reaches the customer thread.

See also