Skip to main content
POST
/
v1
/
v2
/
conversations
/
{conversation_id}
/
close
Close a v2 conversation
curl --request POST \
  --url https://api-sandbox.featherhq.com/v1/v2/conversations/{conversation_id}/close \
  --header 'Content-Type: application/json' \
  --header 'x-api-key: <api-key>' \
  --data '{}'
{
  "id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "organization_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "end_user_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "channel": "<string>",
  "message_count": 123,
  "started_at": "2023-11-07T05:31:56Z",
  "created_at": "2023-11-07T05:31:56Z",
  "updated_at": "2023-11-07T05:31:56Z",
  "external_session_id": "<string>",
  "session_type": "live",
  "subject": "<string>",
  "assigned_agent_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "retention_policy_id": "3c90c3cc-0d44-4b50-8888-8dd25736052a",
  "summary": "<string>",
  "metadata": {},
  "context_variables": {},
  "first_message_at": "2023-11-07T05:31:56Z",
  "last_message_at": "2023-11-07T05:31:56Z",
  "ended_at": "2023-11-07T05:31:56Z",
  "closed_at": "2023-11-07T05:31:56Z",
  "ttl_expires_at": "2023-11-07T05:31:56Z",
  "retention_expires_at": "2023-11-07T05:31:56Z",
  "archived_at": "2023-11-07T05:31:56Z",
  "memory_synced": false,
  "duration_ms": 123,
  "summary_preview": "<string>",
  "has_recording": false,
  "eval_summary": {
    "total": 0,
    "succeeded": 0,
    "failed": 0,
    "pending": 0,
    "critical_total": 0,
    "critical_succeeded": 0,
    "critical_failed": 0,
    "critical_pending": 0,
    "eval_status": "none"
  }
}

Authorizations

x-api-key
string
header
required

Path Parameters

conversation_id
string<uuid>
required

Body

application/json
reason

Canonical reasons a voice/runtime session ended.

Stored on ConversationSession.internal_termination_reason via the :class:SessionTerminationReasonType TypeDecorator — Python surfaces the enum, the DB column itself is plain VARCHAR(64) with no Postgres ENUM type and no CHECK constraint, so extending the enum is a Python-only change (no migration needed).

AGENT_INITIATED covers every LLM-driven end (the agent decided the conversation is over). UNKNOWN is the defensive fallback any string that fails to coerce lands on — both at write time (via coerce_termination_reason in src/runtime/contracts.py) and at read time (via :meth:SessionTerminationReasonType.process_result_value when a legacy / drifted value is loaded from the row).

Available options:
voicemail_detected,
silence_timeout,
max_call_duration,
participant_left,
pipeline_exit,
user_requested,
agent_initiated,
resolved,
unresolved,
abandoned,
escalated,
handoff_resolved,
transferred,
error,
unknown,
callee_busy,
callee_no_answer,
callee_unavailable,
callee_declined,
callee_not_found,
sip_failed,
unknown_reason,
client_initiated,
duplicate_identity,
server_shutdown,
participant_removed,
room_deleted,
state_mismatch,
join_failure,
migration,
signal_close,
room_closed,
user_unavailable,
user_rejected,
sip_trunk_failure,
connection_timeout,
media_failure,
agent_error,
dispatch_failed,
token_mint_failed,
sip_dial_failed,
participant_join_timeout,
setup_error,
stale_routing,
superseded,
duplicate_dispatch
Maximum string length: 64

Response

Successful Response

id
string<uuid>
required
organization_id
string<uuid>
required
end_user_id
string<uuid>
required
channel
string
required
status
enum<string>
required
Available options:
queued,
ringing,
active,
paused,
waiting_for_human,
transferred,
awaiting_approval,
closed,
expired,
error,
superseded
priority
enum<string>
required
Available options:
low,
normal,
high,
urgent
message_count
integer
required
started_at
string<date-time>
required
created_at
string<date-time>
required
updated_at
string<date-time>
required
origin
enum<string> | null
Available options:
inbound,
outbound
external_session_id
string | null
session_type
enum<string>
default:live
Available options:
live,
test,
simulation
subject
string | null
assigned_agent_id
string<uuid> | null
retention_policy_id
string<uuid> | null
summary
string | null
metadata
Metadata · object
context_variables
Context Variables · object
first_message_at
string<date-time> | null
last_message_at
string<date-time> | null
ended_at
string<date-time> | null
closed_at
string<date-time> | null
ttl_expires_at
string<date-time> | null
retention_expires_at
string<date-time> | null
archived_at
string<date-time> | null
memory_synced
boolean
default:false
duration_ms
integer | null
summary_preview
string | null
has_recording
boolean
default:false
eval_summary
SessionEvalSummary · object

Rollup of eval runs that targeted a session.

succeeded = runs where status='completed' AND every score has passed=true. failed = total - succeeded - pending (failed-status runs + completed-but-not-all-passed). pending = runs still queued or running.

The critical_* counterparts restrict the same aggregation to runs whose binding was marked is_critical=True (snapshotted onto the run). They drive the session headline pill — non-critical evals still run and display but don't move the verdict. eval_status collapses the critical counts to a single headline label (none when no criticals are configured).