Search every conversation and call in one list
The Interactions page answers one question — “Search every conversation and call across messaging and voice in one recency-ordered, exportable list.” Before this page, reconstructing a customer’s full history meant paging Conversations for messaging and Call logs for voice separately and merging the two timelines by hand. Interactions merges both into a single list you can filter, page through, and export. Use Interactions when you need the whole picture:- Customer support — pull up every touchpoint for a contact by name, phone, or email, regardless of channel.
- Incident review — isolate one interaction type (conversations only or calls only), one channel, or a status window.
- Regulatory or QA sampling — export a filtered slice to CSV and hand it to an auditor.
What an “interaction” is
An interaction is not a separate record in your workspace. It is a derived projection — the API unions your existing conversation rows with your existing call-log rows and returns one merged list. One feed replacement when you would otherwise merge conversations and calls by hand; there is no third collection to keep in sync. That means:- No new write path. A conversation or call written through its own channel lands in the unified list automatically.
- No duplication. A conversation and a call stay the records they are; the unified view only joins them for reading and export.
- Two different row types. A conversation row points back to the inbox thread; a call row points back to the call-detail page. The row’s
typefield (conversationorcall) tells the two apart.
Why one recency-ordered list beats two surfaces
Conversations and calls both record customer touchpoints; the inbox lists one and the voice console the other. Before the unified list, answering “what happened with this customer this week?” meant opening both surfaces, applying the same date or contact filter in each, and comparing timestamps across two browser tabs. One recency-ordered feed removes that merge — the most recent touch across every channel is one page, sorted so the newest activity is first. The ordering key is the same on both arms: a conversation row is stamped by its latest message, a call row is stamped by the call start. Sorting by that timestamp descending puts whichever channel spoke last at the top of the list.Permissions
Search and export have deliberately asymmetric gates:- Search — owner, admin, developer, and viewer can all run the search. It reads the same rows the conversations list and call log expose to those roles individually, so it inherits the same read posture as global search.
- CSV export — gated to owner, admin, and developer roles holding the
contacts:readpermission scope. A bulk, org-wide pull of contact-linked interaction history across every channel in one response — higher blast radius than a single-page view — so the lift is tighter.
The 403 toast edge case
When a viewer selects Export CSV, the API rejects the bulk pull with a403 Permission denied response and the dashboard surfaces it as a friendly toast explaining the gate, rather than the raw error page:
contacts:read.
Filters and query syntax
All filters combine with AND semantics. The dashboard exposes them as a free-text search box, chip strips, and a date-range preset; the API accepts the same parameters as query strings onGET /interactions. All combine — AND across axes, OR within one list.
Unknown channel, type, or status values are ignored rather than rejected, and an expired or unparseable cursor degrades to the first page instead of failing — a stale chip or token never hard-fails the query.
Recency ordering and the composite keyset cursor
Rows sort bylast_activity_at descending — the most recent customer touch first, mixed across the unified conversation and call arms. Cursor pagination walks that same ordering without skipping rows that share a timestamp.
Pagination is a composite (last_activity_at, id) keyset cursor, the same base64-<ts>|<id> opaque token every other Orbit list uses. Because id ties break the timestamp tie, two interactions that land at the same second page through in a stable order — a page never skips or repeats a row when multiple events share the same recency time.
limitdefaults to 25, maximum 100.- The response carries
meta.pagination.cursorandmeta.pagination.has_more. Pass the opaque token back as?cursor=to fetch the next page; stop whenhas_moreisfalse. - The dashboard’s Load more button walks the same cursor chain.
- A supplied-but-unparseable cursor degrades to the first page rather than erroring — search stays available.
last_activity_at and id back — opaque base64 on the wire, (ts, id) composite inside.
Walk the dashboard
- Open the dashboard and select Interactions on the sidebar.
- Type a contact name, phone, or email into the search box; clear it to widen back.
- Chip-check the interaction type (Conversation, Call) and channel (SMS, WhatsApp, …, Voice) — AND across chips, OR within one chip row; All clears that chip set.
- Pick a date-range preset (Last 24h / 7 days / 30 days / All time) on the row below the search box.
- The status column renders a lifecycle pill (Active, Closed, Completed, No answer) and, on conversation rows with a delivery signal, a second delivery pill (Delivered, Failed, Undelivered) so the channel and the message health both show at a glance.
- The Contact column deep-links a row back to the contact record; the contact name resolves once and reuses for the link.
- Confirm the Preview column shows a plain-text snippet (HTML markup stripped) — email rows usually the thread body.
- Click Load more to walk the cursor; click Export CSV in the header to download the same filtered view (gated — see Permissions).
CSV export
Select Export CSV in the page header to download the currently filtered result set. The export applies the same filters you see on screen, so narrow first, then export.- Columns, in order:
id,type,channel,status,delivery_status,contact_id,contact_name,contact_phone,contact_email,direction,preview,last_activity_at. - Filename:
<stem>-YYYY-MM-DD.csv,attachmentdisposition,Cache-Control: no-store. The API accepts an optionalfilenamestem (sanitised to[A-Za-z0-9._-], capped at 80 characters, defaultinteractions). - Row ceiling: 20,000 rows per export. If the result set is larger, the CSV is truncated at the cap and the response carries an
X-Export-Truncated: trueheader — narrow the date range or channel filter and re-export. - Rate limit: 5 exports per minute, matching the ad-hoc audience export ceiling.
- Audit: every export writes an audit entry with the row count, whether the result was truncated, and the applied cap.
PII redaction applies to both doors
If your organisation has opted into transcript PII redaction under Settings → Privacy, masked values (contact_name, contact_phone, contact_email, preview) are masked identically on the on-screen list and inside the CSV. Redacting only the export would be no protection — a viewer could read the same columns on the search page. One redaction gate covers both surfaces.
Back-links: jump to the inbox thread or the call detail
A row is a pointer: the search list surfaces the contact and latest activity; opening the full record happens elsewhere.- Jump to the inbox thread when the row
typeisconversationand itshrefpoints into the inbox — pick it to open the thread and send a reply. - Jump to the call-log detail when the row
typeiscalland itshrefpoints into the call detail page — pick it to review the disposition, the recording (when your role can see it), or the per-leg log. - Use the Contact deep link when the next step is the full contact profile rather than the thread.
Troubleshooting
- Empty results — Loosen one filter at a time. A status value from one arm (a conversation status against calls, or vice versa) matches zero rows on the other; dropping the status chip is the fastest check. Also confirm the date-range preset — a 24h window on a quiet workspace returns nothing.
- 403 on export — You hold a viewer role or lack the
contacts:readscope. Search is unaffected. Request an owner/admin/developer run the export or grant the scope. - A channel is missing from the list — The channel vocabulary matches the inbox filter list. Voice rows only appear when the
voicechannel is included (or no channel filter is set); filtering to only messaging channels strips calls and vice versa viatypes. - CSV has fewer rows than the list shows — The 20,000-row ceiling. Narrow the filters; the
X-Export-Truncatedheader confirms truncation.
See also
- Unified interaction model concept — the projection definition and column semantics.
- Interactions export model concept — the gate, audit, and redaction semantics behind the CSV pull.
- Contact timeline — the per-contact counterpart when a single contact’s full history is the target.
- Conversation archive — natural-language search plus the per-conversation bulk export.
- Export conversations as signed vCon containers — the per-thread, tamper-evident counterpart to this bulk CSV.
- Search message history — fielded single-message lookups by provider reference.
- Inbox setup — the operator surface the channel filters mirror.