Interaction Search deep dive
The Interactions page is the unified, cross-channel search surface for your workspace. It lists every messaging conversation and every voice call in one recency-ordered feed, applies the same filters to both arms, and exports the result to CSV. This guide covers the surface end to end: navigation, auth, the data model, filter combinations, the export contract, and how it relates to global search. Open it from the dashboard sidebar under Interactions, or callGET /api/v1/interactions directly.
1. Where the surface lives and who can use it
Navigation
- Dashboard: Interactions in the left sidebar, at
/interactions. - API:
GET /api/v1/interactionsfor the paginated search;GET /api/v1/interactions/export.csvfor the bulk CSV export.
Auth posture
The page splits read and export into two deliberate gates:
The search list inherits the same read posture as the conversations list, call log, and
/search/global: any authenticated workspace member can read it. The CSV export is a bulk, org-wide pull of contact-linked interaction history, so it is gated more tightly.
The friendly 403 for viewers
When a viewer clicks Export CSV, the API returns403 Permission denied and the dashboard shows a toast instead of a raw error page:
contacts:read.
2. The unified cross-channel model
An interaction is not a new record type. It is a derived projection that unions two existing record families:- Conversation rows — inbox threads from every messaging channel (SMS, WhatsApp, email, RCS, Viber, Instagram, Messenger, Telegram, LINE, web chat, Apple Messages, WeChat, Kakao, Zalo, and the AI agent channel). Each row carries the thread lifecycle status and the delivery status of its latest message.
- Call rows — voice call-log entries, synthesized with
channel: "voice". Each row carries the call disposition and direction, and deep-links into the call-detail page.
How recency ordering works
Rows sort bylast_activity_at descending:
- A conversation row is stamped by its latest message time (
last_message_at), falling back tocreated_at. - A call row is stamped by the call start (
ended_at→answered_at→started_at→created_at), so a long running call enters the list when it begins, not when it ends.
(last_activity_at, id) keyset cursor, so two rows that share the same second page through in a stable order without skips or duplicates.
Voice transcripts and message exchanges together
Voice calls do not carry a message preview; they render as aCall badge with direction. The transcript and recording live on the call-detail page behind the row. Message exchanges render a plain-text snippet of the latest message (HTML stripped for email). The list’s job is to point, not replay.
Relationship to global search
Both surfaces answer “find something” across pillars, but they differ in scope and output:/search/globalis the Cmd-K command palette. It returns ranked matches across contacts, conversations, calls, agents, numbers, and segments, capped per pillar, with no export.- Interactions is a dedicated page over the conversation + call union. It returns one recency-ordered list, supports deep filters, and exports to CSV.
3. Filter combinations
All filters combine with AND across axes and OR within one chip row. Unknown channel, type, or status values are ignored rather than rejected.By channel
The channel chip row mirrors the inbox vocabulary:sms, whatsapp, email, rcs, viber, instagram, messenger, telegram, line, web_chat, apple_messages, wechat, kakao, zalo, video, agent, voice.
voice is the gate on call rows. Select only messaging channels and calls drop out. Select voice to include calls; select only voice to see calls exclusively.
By direction
Direction applies only to call rows. Conversation rows have no single direction, so their direction isnull. Filter by direction in the API with inbound or outbound to isolate incoming or outgoing calls.
By date window
The dashboard offers presets: Last 24h, Last 7 days (default), Last 30 days, All time. The API accepts explicit ISO-8601 UTC bounds viasince and until. until must be on or after since.
Per contact
- Use the search box for a prefix-anchored match against the linked contact’s name, phone, or email.
- Use the
contact_idquery parameter to restrict to one contact exactly. - Click the Contact column in the dashboard to open the contact record.
By agent
Filter by theagent channel to surface AI agent conversations in the unified list. The channel acts like any other channel chip: combine it with a date window or contact to see everything an agent handled in a given period.
By status
Thestatuses filter is free-form because conversation and call vocabularies differ. A status that exists on one arm matches zero rows on the other rather than failing the request. Common conversation statuses include active and closed; common call statuses include completed, no_answer, busy, and declined.
API example: combine channel, type, and date
4. CSV export
Select Export CSV in the page header to download the currently filtered result set. Narrow first, then export.What is gated
Only owner, admin, and developer roles withcontacts:read can export. Viewers see the friendly 403 toast described above. The export is rate-limited to 5 per minute.
Column contract
Columns are emitted in this order:Row-order guarantee
CSV rows follow the same recency ordering as the on-screen list:last_activity_at descending, with id as the tie-breaker. The export walks the same cursor chain the dashboard uses.
Limits and truncation
- Ceiling: 20,000 rows per export.
- If the result set exceeds the ceiling, the CSV is truncated and the response carries
X-Export-Truncated: true. - Filename:
<stem>-YYYY-MM-DD.csv. The optionalfilenamequery parameter is sanitized to[A-Za-z0-9._-]and capped at 80 characters. - Audit: every export writes an audit entry with row count, truncation flag, and applied cap.
PII redaction
If your workspace has opted into transcript PII redaction under Settings → Privacy, the same masking applies to the CSV and the on-screen list.contact_name, contact_phone, contact_email, and preview are masked identically in both surfaces.
5. Walkthrough: find the call where the customer disputed the charge
A customer emailed support saying they disputed a charge during a call last week. You need the call row, not the email thread.- Open Interactions.
- Type the customer’s name or phone into the search box.
- Chip Call under type and voice under channel.
- Pick Last 7 days.
- Look for the call row around the date the customer mentioned. The Preview column shows
Voice call; the Channel / Status column showsvoiceand the disposition. - Click the row to open the call-detail page and review the recording or transcript.
6. Walkthrough: export a slice as a viewer and hit the 403 fallback
A viewer is asked to pull last month’s WhatsApp interactions for a QA review.- Open Interactions.
- Chip Conversation under type and whatsapp under channel.
- Pick Last 30 days.
- Click Export CSV.
- The dashboard shows the friendly 403 toast because the viewer role cannot export.
- The viewer copies the current filter state from the page and asks an owner or admin to run the export, or requests the
contacts:readscope.
7. Troubleshooting
If the list or export behaves unexpectedly, start with these checks:- Empty results — Loosen one filter at a time. A status value from one arm matches zero rows on the other. Confirm the date-range preset is not too narrow.
- Calls are missing —
voicemust be in the channel chip set, or no channel filter at all. The type filter must also include Call. - Export fails with 403 — You hold a viewer role or lack
contacts:read. Search is unaffected. - CSV has fewer rows than expected — You hit the 20,000-row ceiling; narrow the filters and re-export. The
X-Export-Truncatedheader confirms truncation.
See also
- Search every conversation and call in one list — the original reference for the unified list.
- Walk the Interactions console — a tour of the filter strip and columns.
- Find a conversation across channels — end-to-end workflow from query to ticket hand-off.
- Global search fan-out — the cross-pillar search model Interactions shares its read posture with.
- Unified interaction model — the projection definition behind the unified list.