---
title: "Close a v2 conversation"
method: POST
path: "/v1/v2/conversations/{conversation_id}/close"
tags: ["runtime v2"]
---

# Close a v2 conversation

`POST /v1/v2/conversations/{conversation_id}/close`

## Path parameters

- `conversation_id` string, uuid, required

## Request body

- SessionClose
  - `reason` union
    - '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' — 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).
    - string

## Response `200`

Successful Response

- SrcConversationSchemasSessionResponse
  - `id` string, uuid, required
  - `organization_id` string, uuid, required
  - `end_user_id` string, uuid, required
  - `channel` string, required
  - `origin` 'inbound' | 'outbound', nullable
  - `external_session_id` string, nullable
  - `status` 'queued' | 'ringing' | 'active' | 'paused' | 'waiting_for_human' | 'transferred' | 'awaiting_approval' | 'closed' | 'expired' | 'error' | 'superseded', required
  - `session_type` 'live' | 'test' | 'simulation'
  - `priority` 'low' | 'normal' | 'high' | 'urgent', required
  - `subject` string, nullable
  - `assigned_agent_id` string, uuid, nullable
  - `retention_policy_id` string, uuid, nullable
  - `summary` string, nullable
  - `metadata` object
  - `context_variables` object
  - `message_count` integer, required
  - `first_message_at` string, date-time, nullable
  - `last_message_at` string, date-time, nullable
  - `started_at` string, date-time, required
  - `ended_at` string, date-time, nullable
  - `closed_at` string, date-time, nullable
  - `ttl_expires_at` string, date-time, nullable
  - `retention_expires_at` string, date-time, nullable
  - `archived_at` string, date-time, nullable
  - `memory_synced` boolean
  - `created_at` string, date-time, required
  - `updated_at` string, date-time, required
  - `duration_ms` integer, nullable
  - `summary_preview` string, nullable
  - `has_recording` boolean
  - `eval_summary` SessionEvalSummary — 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).
    - `total` integer
    - `succeeded` integer
    - `failed` integer
    - `pending` integer
    - `critical_total` integer
    - `critical_succeeded` integer
    - `critical_failed` integer
    - `critical_pending` integer
    - `eval_status` 'success' | 'partial' | 'failure' | 'pending' | 'none'

## Other responses

- `400` — Bad request
- `401` — Authentication required
- `404` — Resource not found
- `422` — Validation Error

---

[API](https://skmtc.net/oneloop-hq/apis/feather-api.md) · [All operations](https://skmtc.net/oneloop-hq/apis/feather-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/oneloop-hq/feather-api/versions/888bdd5c076e/schema)
