> ## Documentation Index
> Fetch the complete documentation index at: https://docs.answeringagent.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversations

> Search calls, texts, website chats, and emails, read transcripts, and download call recordings.

A conversation is one customer contact: a phone call, a text thread, a website chat, or an email thread. When the AI texts a caller during or after a call, those texts belong to the call's conversation.

## Search conversations

```
GET /conversations
```

[Try it in the playground](/api-reference/conversations/search-conversations).

Returns conversation summaries, most recent activity first. To read what was said, [get the conversation](#get-a-conversation).

<ParamField query="query" type="string">
  Matches the customer's name, phone number, or email, or words in the title, summary, or category. Up to 100 characters.
</ParamField>

<ParamField query="channel" type="string">
  One of `phone`, `text`, `web_chat`, or `email`. Returns conversations that happened on that channel. A call the customer replied to by text matches both `phone` and `text`.
</ParamField>

<ParamField query="range" type="string">
  Created within this window: `today`, `yesterday`, `7d`, `14d`, `30d`, `90d`, `365d`, `mtd`, or `ytd`. Every window starts at midnight in your team's timezone. See [time ranges](/api/overview#pages-and-time-ranges). Leave it out for all time.
</ParamField>

<ParamField query="limit" type="integer" default="10">
  Results per page, 1 to 50.
</ParamField>

<ParamField query="page" type="integer" default="1">
  Page number. Use `next_page` from the previous response.
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://answeringagent.com/api/v1/conversations?channel=phone&range=7d&limit=2" \
    -H "X-API-KEY: $ANSWERING_AGENT_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const params = new URLSearchParams({ channel: 'phone', range: '7d', limit: '2' });
  const res = await fetch(`https://answeringagent.com/api/v1/conversations?${params}`, {
    headers: { 'X-API-KEY': process.env.ANSWERING_AGENT_API_KEY },
  });
  if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
  const { conversations, next_page } = await res.json();
  ```
</CodeGroup>

```json theme={null}
{
  "total_matching": 214,
  "page": 1,
  "next_page": 2,
  "conversations": [
    {
      "id": 184532,
      "url": "https://answeringagent.com/dashboard/conversations/184532",
      "channel": "phone",
      "channels": ["phone", "text"],
      "started_at": "2026-10-05T14:21:07.000Z",
      "last_activity_at": "2026-10-05T14:26:40.000Z",
      "title": "Cancel monthly membership",
      "summary": "Dana called to cancel her Unlimited plan before the next charge on the 12th. The AI offered one free month, which she declined, and texted her the cancellation form.",
      "category": "cancellation",
      "customer": { "name": "Dana Ruiz", "phone": "+15125550118", "email": "dana.ruiz@example.com" },
      "phone_line": { "id": 2181, "name": "Westside Wash", "phone_number": "+15125550142" },
      "duration_seconds": 214,
      "has_recording": true
    },
    {
      "id": 184498,
      "url": "https://answeringagent.com/dashboard/conversations/184498",
      "channel": "phone",
      "channels": ["phone"],
      "started_at": "2026-10-05T13:02:51.000Z",
      "last_activity_at": "2026-10-05T13:02:51.000Z",
      "title": "Hours on Sunday",
      "summary": "Caller asked whether the Lamar location is open Sunday. The AI gave the Sunday hours.",
      "category": "hours_status",
      "customer": { "name": null, "phone": "+15125550190", "email": null },
      "phone_line": { "id": 2182, "name": "Lamar Blvd", "phone_number": "+15125550177" },
      "duration_seconds": 48,
      "has_recording": true
    }
  ]
}
```

### Conversation fields

<ResponseField name="id" type="integer">
  The conversation ID. Use it to get the conversation or its recording.
</ResponseField>

<ResponseField name="url" type="string">
  The conversation in the dashboard.
</ResponseField>

<ResponseField name="channel" type="string | null">
  The channel the conversation started on: `phone`, `text`, `web_chat`, or `email`.
</ResponseField>

<ResponseField name="channels" type="string[]">
  Every channel the conversation happened on. A call the customer replied to by text lists `phone` and `text`. Texts the AI sent during or after a call appear in `written.messages` but don't add `text`.
</ResponseField>

<ResponseField name="started_at" type="string | null">
  When the conversation started, as an ISO 8601 UTC timestamp.
</ResponseField>

<ResponseField name="last_activity_at" type="string | null">
  The latest message, or `started_at` when there were no later messages. `null` only when both are missing.
</ResponseField>

<ResponseField name="title" type="string | null">
  A short title the AI wrote. Up to 200 characters.
</ResponseField>

<ResponseField name="summary" type="string | null">
  The AI's summary. Up to 1,500 characters.
</ResponseField>

<ResponseField name="category" type="string | null">
  The conversation category key, such as `cancellation`, `billing`, `damage_claim`, `lost_items`, `sales`, `scheduling`, `hours_status`, `service_status`, `account_update`, `general_questions`, `job_seeking`, or `other`. [`GET /reports/metrics`](/api/reports#list-the-metrics) lists every key with its label under `categories`. Older conversations can have a retired key that is not in that list.
</ResponseField>

<ResponseField name="customer" type="object">
  The customer's `name`, `phone`, and `email`. Any of them can be `null`.
</ResponseField>

<ResponseField name="phone_line" type="object | null">
  The phone line (location) that took the conversation: `id`, `name`, and `phone_number`. `name` and `phone_number` can be `null`.
</ResponseField>

<ResponseField name="duration_seconds" type="integer | null">
  Call length in seconds. `null` for texts, chats, and emails.
</ResponseField>

<ResponseField name="has_recording" type="boolean">
  `true` when [`GET /conversations/{conversation_id}/recording`](#download-a-call-recording) has audio to stream for this call. `false` for texts, chats, emails, and calls that were not recorded. For some calls the recording provider stores the audio and can delete it, so `true` can still get a `404`.
</ResponseField>

## Get a conversation

```
GET /conversations/{conversation_id}
```

[Try it in the playground](/api-reference/conversations/get-a-conversation).

Returns one conversation with every [conversation field](#conversation-fields), plus the questions the customer asked, its task, and the full transcript.

<ParamField path="conversation_id" type="integer" required>
  The conversation ID.
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl https://answeringagent.com/api/v1/conversations/184532 \
    -H "X-API-KEY: $ANSWERING_AGENT_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch('https://answeringagent.com/api/v1/conversations/184532', {
    headers: { 'X-API-KEY': process.env.ANSWERING_AGENT_API_KEY },
  });
  if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
  const conversation = await res.json();
  ```
</CodeGroup>

```json theme={null}
{
  "id": 184532,
  "url": "https://answeringagent.com/dashboard/conversations/184532",
  "channel": "phone",
  "channels": ["phone", "text"],
  "started_at": "2026-10-05T14:21:07.000Z",
  "last_activity_at": "2026-10-05T14:26:40.000Z",
  "title": "Cancel monthly membership",
  "summary": "Dana called to cancel her Unlimited plan before the next charge on the 12th. The AI offered one free month, which she declined, and texted her the cancellation form.",
  "category": "cancellation",
  "customer": { "name": "Dana Ruiz", "phone": "+15125550118", "email": "dana.ruiz@example.com" },
  "phone_line": { "id": 2181, "name": "Westside Wash", "phone_number": "+15125550142" },
  "duration_seconds": 214,
  "has_recording": true,
  "questions": [
    {
      "question": "Will I be charged on the 12th if I cancel today?",
      "answer": "No. Cancelling before the billing date stops the next charge.",
      "answered": true
    }
  ],
  "task": {
    "id": "conversation-184532",
    "url": "https://answeringagent.com/dashboard/conversations/184532",
    "title": "Cancel monthly membership",
    "status": "open",
    "assignee": { "id": 9034, "name": "Priya Shah" },
    "category": "cancellation",
    "priority": "high",
    "created_at": "2026-10-05T14:21:07.000Z",
    "customer": { "name": "Dana Ruiz", "phone": "+15125550118", "email": "dana.ruiz@example.com" },
    "conversation": {
      "id": 184532,
      "url": "https://answeringagent.com/dashboard/conversations/184532",
      "channel": "phone",
      "phone_line": { "id": 2181, "name": "Westside Wash", "phone_number": "+15125550142" }
    },
    "form": null,
    "description": "Dana Ruiz wants to cancel her Unlimited membership before the charge on the 12th. She is moving out of state and declined the free-month offer. Confirm the cancellation in the POS and reply by text."
  },
  "transcript": {
    "truncated": false,
    "omitted_earlier_turns": 0,
    "turns": [
      { "speaker": "ai", "text": "Thanks for calling Westside Wash. How can I help?", "seconds_into_call": 0 },
      { "speaker": "customer", "text": "Hi, I need to cancel my membership.", "seconds_into_call": 4 },
      { "speaker": "ai", "text": "I can help with that. Before you go, we can give you one month free. Would that help?", "seconds_into_call": 9 },
      { "speaker": "customer", "text": "No thanks, I'm moving.", "seconds_into_call": 15 }
    ]
  },
  "written": {
    "truncated": false,
    "omitted_messages": 0,
    "messages": [
      {
        "from": "business",
        "channel": "text",
        "text": "Here is the cancellation form for your Westside Wash membership: https://example.com/cancel",
        "sent_at": "2026-10-05T14:24:31.000Z"
      },
      {
        "from": "customer",
        "channel": "text",
        "text": "Submitted it. Thanks!",
        "sent_at": "2026-10-05T14:26:40.000Z"
      }
    ]
  }
}
```

<ResponseField name="questions" type="object[]">
  Questions the customer asked, each with the `question`, the `answer` given, and whether it was `answered`. `answer` can be `null`.
</ResponseField>

<ResponseField name="task" type="object | null">
  The task this conversation created, in the same shape as [Get a task](/api/tasks#get-a-task), with its `description`. `null` when it created no task.
</ResponseField>

<ResponseField name="transcript" type="object | null">
  The spoken transcript of a phone call. `null` for texts, chats, and emails.

  <Expandable title="transcript fields">
    <ResponseField name="turns" type="object[]">
      Each turn has a `speaker` (`ai`, `customer`, or `unknown`), the `text`, and `seconds_into_call`.
    </ResponseField>

    <ResponseField name="truncated" type="boolean">
      `true` when a very long call was cut.
    </ResponseField>

    <ResponseField name="omitted_earlier_turns" type="integer">
      How many earlier turns were cut to fit a very long call. `0` unless `truncated` is `true`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="written" type="object | null">
  Texts, chat messages, and emails in the conversation. `null` when there are none. A phone call with follow-up texts has both `transcript` and `written`.

  <Expandable title="written fields">
    <ResponseField name="messages" type="object[]">
      Each message has `from` (`customer` or `business`), `channel` (`text`, `web_chat`, `email`, or occasionally `phone`), `text`, and `sent_at`. A business message that did not reach the customer also has `"not_delivered": true`.
    </ResponseField>

    <ResponseField name="truncated" type="boolean">
      `true` when a very long thread was cut.
    </ResponseField>

    <ResponseField name="omitted_messages" type="integer">
      How many messages were left out.
    </ResponseField>
  </Expandable>
</ResponseField>

A conversation that does not exist, or that the key's owner cannot see, returns `404`.

## Download a call recording

```
GET /conversations/{conversation_id}/recording
```

[Try it in the playground](/api-reference/conversations/download-a-call-recording).

Returns the call audio. The response body is the audio file, not JSON. The format depends on how the call was recorded, such as MP3 or Ogg. Read the `Content-Type` header.

<ParamField path="conversation_id" type="integer" required>
  The conversation ID of a phone call.
</ParamField>

<ParamField header="Range" type="string">
  Optional. Request part of the file, such as `bytes=0-1048575`. The response is then `206` with a `Content-Range` header.
</ParamField>

<CodeGroup>
  ```bash cURL theme={null}
  curl https://answeringagent.com/api/v1/conversations/184532/recording \
    -H "X-API-KEY: $ANSWERING_AGENT_API_KEY" \
    -o call-184532-recording
  ```

  ```javascript JavaScript theme={null}
  import { writeFile } from 'node:fs/promises';

  const res = await fetch('https://answeringagent.com/api/v1/conversations/184532/recording', {
    headers: { 'X-API-KEY': process.env.ANSWERING_AGENT_API_KEY },
  });
  if (!res.ok) throw new Error(`${res.status}: ${await res.text()}`);
  await writeFile('call-184532-recording', Buffer.from(await res.arrayBuffer()));
  ```
</CodeGroup>

Returns `404` when the conversation has no recording. Check `has_recording` on the conversation first. Texts, chats, emails, and calls that were not recorded have none. Recordings come back as MP3 (`audio/mpeg`) or Ogg (`audio/ogg`). Read the `Content-Type` header. A `Range` header that falls outside the file returns `416` when the recording provider supports byte ranges. Otherwise it returns `404`. If the recording provider is down, the API returns `502` or `503` for most recordings and `404` or `500` for some, so retry later before treating a recording as missing.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.