# Conversations

> Threads between one of your Ody numbers and an outside party: list them, read the full timeline, and mark them open or done.

Source: https://dev.ody.co/api/conversations

A **conversation** is one thread between one of your Ody numbers and an outside party (one person, or several people in a group text). Every message, call, voicemail, internal note and system event in the thread is an **activity**, in time order. It is the same object your team sees as a row in the inbox.

## The conversation object

- `id` *uuid* — Unique identifier.
- `inboxId` *uuid* — The inbox the thread lives in.
- `numberE164` *string | null* — The Ody number on your side of the thread.
- `participants` *array of strings* — The outside party's E.164 numbers.
- `contactName` *string* — Display name: the contact's name, or the formatted number.
- `status` *"open" | "done"* — Inbox state. A new inbound message re-opens a `done` thread.
- `assigneeUid` *string | null* — Teammate the thread is assigned to.
- `lastActivityAt` *timestamp* — When the latest activity happened.
- `preview` *string | null* — Snippet of the latest activity.
- `unread` *integer* — Unread count for the key's creator.

The conversation object:

```json
{
  "id": "c4f1a2b3-5d6e-4f70-8a9b-0c1d2e3f4a5b",
  "inboxId": "1e2d3c4b-5a69-4788-9a0b-1c2d3e4f5a6b",
  "numberE164": "+15125550100",
  "participants": ["+15125550123"],
  "contactName": "Ada Lovelace",
  "status": "open",
  "assigneeUid": null,
  "lastActivityAt": "2026-10-14T18:05:42.000Z",
  "preview": "Can I move my appointment to Friday?",
  "unread": 1
}
```

## The activity object

- `id` *uuid* — Unique identifier.
- `type` *string* — `message`, `call`, `voicemail`, `internal_note` or `system`.
- `direction` *"inbound" | "outbound" | null* — `null` for notes and system events.
- `authorUid` *string | null* — The teammate who sent it, if any.
- `body` *string | null* — Message text, or the note's text.
- `media` *array* — Attachments: `url` (a short-lived signed link), `contentType`, `size`, `filename`.
- `deliveryStatus` *string | null* — For messages: `queued`, `sent`, `delivered`, `failed`, `received`, or `simulated` (sent with a test key).
- `call` *object | null* — For calls and voicemails: status, duration, recording, AI summary and so on.
- `callTranscript` *array | null* — Speaker-labelled transcript turns, once transcription finishes.
- `aiTags` *array of strings* — Labels the AI attached (for example `appointment`).
- `createdAt` *timestamp* — ISO 8601.

**`GET /v1/api/conversations`**

### List conversations

Returns conversations with the most recent activity first. Results are [cursor-paginated](https://dev.ody.co/api/pagination).

**Scope:** `conversations:read`

**Query parameters**

- `status` *"open" | "done"* — Filter by inbox state. Omit for both.
- `limit` *integer* — 1–100, default 50.
- `cursor` *string* — `nextCursor` from the previous page.

**Returns** `{ conversations: Conversation[], nextCursor: string | null }`.

cURL:

```bash
curl "https://api.ody.co/v1/api/conversations?status=open&limit=25" \
  -H "Authorization: Bearer $ODY_API_KEY"
```
TypeScript:

```ts
const { conversations } = await ody.conversations.list({ status: "open", limit: 25 });
```
Python:

```python
page = client.conversations.list(status="open", limit=25)
```

**`GET /v1/api/conversations/:id`**

### Retrieve a conversation

Returns the conversation and its **full** activity timeline, oldest to newest: messages with media, calls with transcripts and AI summaries, voicemails, notes and system events.

**Scope:** `conversations:read`

**Returns** `{ conversation, activities: Activity[] }`, or `404 not_found`.

cURL:

```bash
curl https://api.ody.co/v1/api/conversations/c4f1a2b3-5d6e-4f70-8a9b-0c1d2e3f4a5b \
  -H "Authorization: Bearer $ODY_API_KEY"
```
TypeScript:

```ts
const { conversation, activities } = await ody.conversations.get("c4f1a2b3-5d6e-4f70-8a9b-0c1d2e3f4a5b");
```
Python:

```python
thread = client.conversations.get("c4f1a2b3-5d6e-4f70-8a9b-0c1d2e3f4a5b")
```

Response:

```json
{
  "conversation": { "id": "c4f1a2b3-…", "status": "open", "contactName": "Ada Lovelace" },
  "activities": [
    {
      "id": "a1…",
      "type": "message",
      "direction": "inbound",
      "body": "Can I move my appointment to Friday?",
      "media": [],
      "deliveryStatus": "received",
      "aiTags": ["appointment"],
      "createdAt": "2026-10-14T18:05:42.000Z"
    }
  ]
}
```

**`PATCH /v1/api/conversations/:id`**

### Update a conversation

Marks the thread `done` (archived from the open inbox) or `open` again. This is the API equivalent of the inbox's **Done** button.

**Scope:** `conversations:write`

**Body**

- `status` *"open" | "done"* **required**

**Returns** `{ conversation: { id, status } }`.

cURL:

```bash
curl -X PATCH https://api.ody.co/v1/api/conversations/c4f1a2b3-5d6e-4f70-8a9b-0c1d2e3f4a5b \
  -H "Authorization: Bearer $ODY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"status":"done"}'
```
TypeScript:

```ts
await ody.conversations.setStatus("c4f1a2b3-5d6e-4f70-8a9b-0c1d2e3f4a5b", "done");
```
Python:

```python
client.conversations.set_status("c4f1a2b3-5d6e-4f70-8a9b-0c1d2e3f4a5b", "done")
```
