The conversation object
Every conversation carries a consistent set of fields:channel and surface are assigned by Feather, not set by you. Creating a
conversation over the API always produces a chat conversation; SMS, voice,
and email conversations are created by their channel adapters.Session types
Feather supports three session types so you can test and simulate behavior without affecting production data:live
A real conversation with a real end user. Counts toward usage and appears in production analytics. Programmatic (API-key) callers can only create
live sessions.test
A developer session that runs the full assistant stack but is excluded from production dashboards. Created from the dashboard (or the
test-chat endpoint).simulation
A scripted run used by simulation suites to evaluate assistant revisions before you activate them.
Status lifecycle
A conversation moves through a defined set of statuses:
Voice and queued sessions add transient states such as
queued, ringing, pending_dispatch, paused, and transferred. Terminal states are closed, expired, error, and superseded. Only non-terminal statuses accept a new turn.
When a turn response comes back with
session_status of awaiting_approval
or waiting_for_human, stop sending new turns and poll
GET /v1/conversations/{id}/messages until the status returns to active or
the conversation closes.Turns
Each exchange within a conversation is a turn. You submit a turn with a singleuser_message, and the assistant produces a reply.
Submit a turn with POST /v1/conversations/{id}/turns:
Request
text, the session_status, and message_seqs (the sequence numbers of the messages this turn produced). Ordering is by message seq, not by timestamp.
Evidence
Evidence
Set
include_evidence: true on the turn request to receive the knowledge-base chunks used to generate the reply. Each evidence entry identifies the source document and chunk. Callers need the CONVERSATIONS_READ permission to see the full evidence view.Streaming
Streaming
POST /v1/conversations/{id}/turns/stream returns a Server-Sent Events stream. You receive delta events (token chunks), an optional member event when a team member becomes active, a final complete event with the full turn result, and an error event on failure.Concurrency
Concurrency
A conversation processes one turn at a time. Submitting a turn while another is in flight returns
409 (retryable) — wait for the first to finish.Channels
All four channels map to the same conversation model. The channel determines how messages arrive and how responses are delivered — the session logic is identical.Chat
Create a conversation with
POST /v1/conversations and submit turns via the API. Powers your web/mobile app and the embeddable webchat widget.SMS
Feather receives inbound SMS on your configured phone number and sends outbound replies. Each number maps to a conversation per end user.
Voice
Inbound and outbound calls are transcribed in real time and answered via TTS. Voice conversations support mid-call transfer to a human.
Inbound emails create or continue a conversation thread; Feather replies from your connected mailbox with full thread history as context.
Threads and identity
Every conversation is associated with anend_user_id. You control how a conversation resolves to an end user when you create it:
end_user_id— reference an existing end user directly. (An unknown ID returns404.)org_external_end_user_id— pass your own stable identifier for the user (a customer ID or an anonymous browser token). Feather get-or-creates an end user for it and bridges it to any existing verified contact (email or phone) for the same person.- Neither — Feather resolves the authenticated caller as the end user.
external_id — chat thread keys
By default there is one open conversation per end user on a given surface. Pass an external_id to run multiple concurrent threads for the same user: a new value opens a new thread, and reusing a value resumes that thread (which makes creation idempotent under retries). external_id is unique per organization for the life of the row.
Human-in-the-loop states
Two statuses represent human-in-the-loop (HITL) scenarios. Both are managed through the dedicated HITL API, not through the conversation endpoints.waiting_for_human
Set when an assistant requests a handoff (the request_human_handoff platform tool, a workflow handoff, or a policy handoff action). The conversation appears under GET /v1/hitl/handoffs. A human relays messages with POST /v1/hitl/handoffs/{id}/messages and ends the handoff with POST /v1/hitl/handoffs/{id}/resolve.
awaiting_approval
Set when a policy with the require_approval action pauses a tool call. The pending item appears under GET /v1/hitl/approvals. A reviewer decides with POST /v1/hitl/approvals/{id}/decide ({"decision": "approve"} or {"decision": "deny"}). On approval the tool call proceeds; on denial the turn is blocked and a safe message is returned.
Next steps
Run a conversation
A hands-on walkthrough of creating a conversation, submitting turns, streaming, and polling.
Conversations API reference
Full reference for conversation, turn, and read endpoints.