interactions
List Interactions
List every conversation of the organization, open and ended, newest first. Use to browse, search or filter the conversation log. Every filter is optional; several narrow together, and one given several values matches any of them. An unrecognized query parameter is refused with 422 naming it.
channel:voicefor calls,textfor messages.state:openorended.channel_key: one or more inbox channels.holder:agent,waitingor a person's id, each matching open conversations only;unassignedis every conversation nobody is answering -- waiting for a person, or ended while it waited.counterparty: the other party's number (any spelling), an address prefix, or the conversation's own id.handed_over: whether a person was ever asked for or ever had it.unreplied=true: an inbound conversation never answered.unanswered=true: an ended conversation the other party never spoke in.draft_test:truenarrows to agent-draft tests,falseexcludes them.min_duration_seconds/max_duration_seconds: ended calls only.record_id: conversations tied to one record.label: one or more label ids; a conversation carrying any of them.prepared_reply:readyoroutdated, or both; an open thread whose agent prepared a reply for a person to review, in that state.since/until: bound when it last moved,[since, until), each with a UTC offset.
A value a filter cannot read is refused with 422. GET /interactions/count
says how many match, with the same filters and no paging. A reader without
conversation_details gets each row without the details-only fields.
query Parameters
inbox_orderlimitoffsetchanneldirectionagent_idanswered_byend_reasonopen_onlyunanswereddraft_testcampaign_idperson_statesinceuntilstatechannel_keyholdercounterpartyhanded_overunrepliedmin_duration_secondsmax_duration_secondsrecord_idlabelprepared_replyList Interactions › Responses
Successful Response
channelVoice and text are two channels over one graph, not two kinds of record.
directionidis_openorg_idThe settings a conversation actually ran with, copied in as values.
An AI profile is not frozen into an agent's published version, so the version
alone cannot say how a conversation sounded. The profile id is kept for
provenance; the provider, model and voice are kept because they are the answer.
used_standby records that a standby served the conversation instead of some
component's first choice — the same fields still describe what was actually
served — and standby_component names which one switched.
Source attribution, as recorded. kind says which of the rest is meaningful;
the others stay unset.
connection_id and address are CHANNEL's pair, and they are two fields for
the reason the thread itself is identified by two: "Threads are per connection;
contacts are per organization" (channels.md). The connection says which of the
organization's accounts the message arrived on — "reply on this thread has to
know which account it leaves by" — and the address says who wrote, in whatever
shape the provider's own namespace has: a phone number in E.164 on WhatsApp, an
opaque user id elsewhere, "decided when each is built".
address is personal data and connection_id is not. The address is the
contact — "on a channel, the contact is their address" — so the retention purge
clears it exactly as it clears number, which is the same datum arriving by a
different road; the connection names one of the organization's own accounts and
survives, like trunk_id beside it.
provider is CHANNEL's third, and it is stored as a value rather than read
off the connection. interactions.md: "a conversation that arrived on a channel
names the provider it arrived on, beside the contact's address", because an
address alone does not say whether the person was reached on WhatsApp, by mail or
somewhere else. It is written by the channel at open, from the provider it is
already speaking to, for the reason the run settings beside it are values too: a
connection is what it is now, and this answers what the conversation arrived on
then. It also keeps connection_id the opaque reference it is — nothing here
dereferences a connection to render a row. Not personal data: it names a kind of
account of the organization's own and nobody outside it, so it survives the purge
exactly as connection_id does.
started_atchannel_keycontact_spokedraft_testlabel_idsrangunrepliedCount Interactions
How many conversations match. Use when you need a count rather than the
rows themselves — GET /interactions' filters, with the same meanings and
the same refusals, and no paging.
query Parameters
channeldirectionagent_idanswered_byend_reasonopen_onlyunanswereddraft_testcampaign_idperson_statesinceuntilstatechannel_keyholdercounterpartyhanded_overunrepliedmin_duration_secondsmax_duration_secondsrecord_idlabelprepared_replyCount Interactions › Responses
Successful Response
countGet Interaction
Fetch one conversation by id. Use when you already have the interaction's
id and need its current state. A reader without conversation_details is sent it
without what only the details view shows (inbox.md rule 22), nor, without
recording, the address of its audio (#968).
path Parameters
interaction_idquery Parameters
agent_idAnswer only if the conversation is this agent's; another agent's is not found.
Answer only if the conversation is this agent's; another agent's is not found.
Get Interaction › Responses
Successful Response
channelVoice and text are two channels over one graph, not two kinds of record.
directionidis_openorg_idThe settings a conversation actually ran with, copied in as values.
An AI profile is not frozen into an agent's published version, so the version
alone cannot say how a conversation sounded. The profile id is kept for
provenance; the provider, model and voice are kept because they are the answer.
used_standby records that a standby served the conversation instead of some
component's first choice — the same fields still describe what was actually
served — and standby_component names which one switched.
Source attribution, as recorded. kind says which of the rest is meaningful;
the others stay unset.
connection_id and address are CHANNEL's pair, and they are two fields for
the reason the thread itself is identified by two: "Threads are per connection;
contacts are per organization" (channels.md). The connection says which of the
organization's accounts the message arrived on — "reply on this thread has to
know which account it leaves by" — and the address says who wrote, in whatever
shape the provider's own namespace has: a phone number in E.164 on WhatsApp, an
opaque user id elsewhere, "decided when each is built".
address is personal data and connection_id is not. The address is the
contact — "on a channel, the contact is their address" — so the retention purge
clears it exactly as it clears number, which is the same datum arriving by a
different road; the connection names one of the organization's own accounts and
survives, like trunk_id beside it.
provider is CHANNEL's third, and it is stored as a value rather than read
off the connection. interactions.md: "a conversation that arrived on a channel
names the provider it arrived on, beside the contact's address", because an
address alone does not say whether the person was reached on WhatsApp, by mail or
somewhere else. It is written by the channel at open, from the provider it is
already speaking to, for the reason the run settings beside it are values too: a
connection is what it is now, and this answers what the conversation arrived on
then. It also keeps connection_id the opaque reference it is — nothing here
dereferences a connection to render a row. Not personal data: it names a kind of
account of the organization's own and nobody outside it, so it survives the purge
exactly as connection_id does.
started_atchannel_keycontact_spokedraft_testlabel_idsrangunrepliedSet Conversation Labels
Put labels on a conversation and take labels off it, by id. Use to sort a conversation: a thread, a call or a text conversation, open or ended, that the caller may read. A conversation carries at most 5; a label already on stays on and one already off stays off. Each change is on the record with who made it.
path Parameters
interaction_idSet Conversation Labels › Request Body
addremoveSet Conversation Labels › Responses
Successful Response
interaction_idlabel_idsGet Trace
The exact path one conversation walked: nodes entered, hops refused, tools run with the values they actually ran with, and everything said. Use when debugging what the agent actually did, not just what was said.
path Parameters
interaction_idquery Parameters
agent_idAnswer only if the conversation is this agent's; another agent's is not found.
Answer only if the conversation is this agent's; another agent's is not found.
Get Trace › Responses
Successful Response
One conversation, as the log shows it.
Get Transcript
The conversation itself — what was said and the gate around it — with none
of the technical trace get_trace also carries. Use when you want what was
said, not the technical trace. Behind interactions alone
(rule 34, 2026-09-28 amendment): a person who can read this interaction's
detail can always read this, whether or not they also hold
interaction_traces.
Not gated by require_flag — open_router. Rule 24's exemption
(_readable_without_interactions_flag): a caller without interactions
still reaches this for a test they started themselves or an Architect
conversation of their own organization; service.describe_transcript raises PermissionDenied
(403, {"detail": "interactions"} — the same body require_flag would
have given) for anything else, including an id that does not exist or
belongs to another organization — indistinguishable on purpose, so a
caller without the flag cannot use 404-vs-403 to learn whether an id it
may not read exists at all.
path Parameters
interaction_idquery Parameters
agent_idAnswer only if the conversation is this agent's; another agent's is not found.
Answer only if the conversation is this agent's; another agent's is not found.
Get Transcript › Responses
Successful Response
One conversation, as the log shows it.
List Labels
List the organization's labels, by name: each with what belongs under it and how many conversations carry it. Use to see the vocabulary a conversation can be sorted by, and what deleting a label would take it off.
List Labels › Responses
Successful Response
descriptionidnameconversation_countCreate Label
Add a label: a name, and one line saying what belongs under it. An owner's or admin's. An organization keeps at most 50, each name once whatever its case.
Create Label › Request Body
namedescriptionCreate Label › Responses
Successful Response
descriptionidnameconversation_countDelete Label
Delete a label: it comes off every conversation it is on, each taking-off on
the record with who did it. An owner's or admin's. GET /labels says how many
conversations that is, to show before confirming.
path Parameters
label_idDelete Label › Responses
Successful Response
Update Label
Rename a label or change its line. An owner's or admin's. The label stays on every conversation it is on.
path Parameters
label_idUpdate Label › Request Body
Update Label › Responses
Successful Response
descriptionidnameconversation_count