---
title: "List Conversations"
method: GET
path: "/conversations"
tags: ["Conversations"]
---

# List Conversations

`GET /conversations`

## Request

- Base URL: `https://api.verdun.ai` (the document declares no server; this is the origin it was published from)
- URL: `https://api.verdun.ai/conversations`
- Auth: HTTP bearer

Keyset page of the caller's threads, newest activity first.

`status` defaults to `open` and is an ADDITION to the brief's route list:
without it an archived thread with no further inbound would be stranded out
of reach.

`order`, `parent_id`, `account_id`, `site_id` and `q` are the inbox's
sort / scope / search controls (owner ask 2026-09-22, "like the History
tab"). All optional; omitted, the list is byte-identical to before.

## Query parameters

- `filter` string
- `status` string
- `limit` integer
- `cursor` string, nullable
- `order` 'desc' | 'asc': Sort by last activity: `desc` newest first (the default), `asc` oldest first. Same vocabulary as GET /events/history. A cursor is only valid under the order it was minted with.
- `parent_id` string, nullable: Only threads of this client. Out of scope matches nothing (never 403).
- `account_id` string, nullable: Only threads whose SITE is under this account. A client-wide thread has no site and so never matches an account.
- `site_id` string, nullable: Only threads on this site.
- `q` string, nullable: Keyword search, History's rules: whitespace-split AND-ed terms, each matched case-insensitively against the contact name, client / account / site names, the customer's number (3+ digits) and every message body in the thread.

## Response `200`

Successful Response

- ConversationListResponse
  - `items` ConversationSummary[], required: One page, newest activity first.
    - `id` string, required: The thread id.
    - `verdun_number` string, required: Our line, E.164.
    - `customer_number` string, required: The customer's number, E.164.
    - `contact_name` string, nullable: Snapshot of the contact at resolution time. Null when the number could not be pinned to one person.
    - `site_contact_id` string, nullable: The resolved contact, if exactly one matched. Null makes the thread read-only (consent cannot be checked without it).
    - `parent_id` string, nullable: Client. Null only for a thread orphaned by a hard client delete.
    - `parent_name` string, nullable: Client name, for the list row.
    - `site_id` string, nullable: Site. **Null means a PARENT-LEVEL thread** — the number belongs to contacts at several sites of one client — not a missing field. It is visible only to a scope holding the whole client.
    - `site_name` string, nullable: Site name, for the list row.
    - `account_id` string, nullable: The SITE'S account, resolved at read time. Null for a client-wide thread and for a site directly under the client.
    - `account_name` string, nullable: Account name, for the list row.
    - `status` 'open' | 'archived', required: An inbound or an outbound reopens an archived thread.
    - `unread_count` integer, required: Conversation-level and SHARED across operators in v1, not per viewer.
    - `last_message_at` string, date-time, required: Last activity. The list's sort key, never null.
    - `last_inbound_at` string, date-time, nullable: Last message from the customer.
    - `last_outbound_at` string, date-time, nullable: Last message from us.
    - `last_message_preview` string, nullable: First 160 characters of the newest body. Staff-only; it never reaches an activity-log entry.
    - `last_message_status` string, nullable: Delivery state of the LAST message, provider vocabulary (queued / sent / delivered / failed / undelivered; `received` on an inbound). Null with no messages. For the list row's badge.
    - `last_message_operator_id` string, nullable: Who sent the last message. Null on an inbound.
    - `last_message_operator_name` string, nullable: Their name, snapshotted when the message was sent. Null on an inbound.
    - `last_message_direction` 'outbound' | 'inbound', nullable: Direction of the previewed message.
    - `claimed_by_operator_id` string, nullable: Who is answering this thread.
    - `claimed_by_name` string, nullable: Their name, for the list row.
    - `claimed_at` string, date-time, nullable: When they claimed it.
    - `last_event` LastEventSummary: The newest incident this thread carries a message about. NO `closed_at` — `events_metadata` HAS NO SUCH COLUMN, and the two things that could stand in for one mean different things: `operator_evaluated` is "a human triaged or dismissed it", `expired_at` is "it aged out unreviewed". Both are exposed and the UI derives "open / closed" rather than the API inventing a single field that erases the distinction.
      - `id` string, required: The event id.
      - `occurred_at` string, date-time, nullable: Ingestor-reported time of the motion. Display only.
      - `created_at` string, date-time, nullable: When we recorded the event — the single DB clock.
      - `operator_evaluated` boolean, required: True once a human triaged or dismissed it.
      - `expired_at` string, date-time, nullable: Set when it aged out unreviewed. NOT the same as a dismissal.
    - `created_at` string, date-time, nullable: When the thread was opened.
    - `updated_at` string, date-time, nullable: Last write to the thread row.
  - `next_cursor` string, nullable: Keyset cursor for the next page. Keyset, not offset: inbound replies reorder this list continuously.

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/verdun/apis/verdun-api.md) - [All operations](https://skmtc.dev/verdun/apis/verdun-api/llms.txt) - [OpenAPI document](https://skmtc.dev/verdun/apis/verdun-api/revisions/00252d8227c1?raw)
