# Reading and syncing conversations

> List, search and read conversations, their transcripts and recordings, keep your own copy up to date, and delete them.

Every call and chat is a **conversation**, read the same way whichever door it came through: the
console, the widget, a phone line, a campaign or this API. Reading needs `conversations:read`; a
transcript also needs `transcripts:read`, and a recording `recordings:read`.

## List them

**curl**

```sh
#!/bin/sh
# List conversations
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/conversations?agent_id=8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c&status=completed&limit=10" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// List conversations
const response = await fetch("https://api.aigently.ai/v1/conversations?agent_id=8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c&status=completed&limit=10", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# List conversations
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://api.aigently.ai/v1/conversations",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
    params={
        "agent_id": "8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c",
        "status": "completed",
        "limit": 10,
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// List conversations
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("GET", "https://api.aigently.ai/v1/conversations?agent_id=8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c&status=completed&limit=10", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// List conversations
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations?agent_id=8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c&status=completed&limit=10"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// List conversations
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.aigently.ai/v1/conversations?agent_id=8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c&status=completed&limit=10")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// List conversations
$curl = curl_init("https://api.aigently.ai/v1/conversations?agent_id=8a1f3c2e-0b6d-4f5e-9a7c-2d4e6f8a0b1c&status=completed&limit=10");
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

Newest first, 20 a page unless you ask for up to 100. Filter by agent, project, channel, direction,
status (repeat it for several), disposition, the analysis's outcome, who ended it, mode, numbers,
campaign, your own `external_id`, and when it started or changed. Each page has `has_more` and a `next_cursor`: send it back
as `cursor`, with the same filters, for the next page. A cursor works only for the key, the mode and
the filters that made it.

## Find one by what was said

**curl**

```sh
#!/bin/sh
# Find conversations by what was said. Each one comes with the passage that matched.
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/conversations?q=refund&limit=10" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// Find conversations by what was said. Each one comes with the passage that matched.
const response = await fetch("https://api.aigently.ai/v1/conversations?q=refund&limit=10", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Find conversations by what was said. Each one comes with the passage that matched.
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://api.aigently.ai/v1/conversations",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
    params={
        "q": "refund",
        "limit": 10,
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Find conversations by what was said. Each one comes with the passage that matched.
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("GET", "https://api.aigently.ai/v1/conversations?q=refund&limit=10", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Find conversations by what was said. Each one comes with the passage that matched.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations?q=refund&limit=10"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Find conversations by what was said. Each one comes with the passage that matched.
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.aigently.ai/v1/conversations?q=refund&limit=10")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Find conversations by what was said. Each one comes with the passage that matched.
$curl = curl_init("https://api.aigently.ai/v1/conversations?q=refund&limit=10");
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

`q` searches the transcripts, the same search as the console's, and needs `transcripts:read` as
well. A word also finds longer words that start with it, so `refund` finds `refunded`. Put a phrase
in quotes to find it as written, and write `-word` to leave out conversations that have the word.
Every other filter still applies. Each result carries `match`: the passage that matched, as plain
text. A key may search 30 times a minute. A conversation can be found about a minute after it ends.

## Read one

**curl**

```sh
#!/bin/sh
# Read a conversation with its transcript
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=transcript" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// Read a conversation with its transcript
const response = await fetch("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=transcript", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Read a conversation with its transcript
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
    params={
        "include": "transcript",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Read a conversation with its transcript
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("GET", "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=transcript", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Read a conversation with its transcript
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=transcript"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Read a conversation with its transcript
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=transcript")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Read a conversation with its transcript
$curl = curl_init("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=transcript");
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

The [conversation](/reference/objects/Conversation) carries its status and how it ended, its
numbers, the values it started with and where each came from, your metadata, the lookup's result,
the answers collected, the analysis, the recording's state and its times. `include=transcript` adds
what was said. The transcript alone:

**curl**

```sh
#!/bin/sh
# Read a transcript
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/transcript" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// Read a transcript
const response = await fetch("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/transcript", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Read a transcript
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/transcript",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Read a transcript
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("GET", "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/transcript", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Read a transcript
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/transcript"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Read a transcript
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/transcript")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Read a transcript
$curl = curl_init("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/transcript");
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

Entries are in order: `user` is the person, `assistant` the agent, `tool` a tool the agent used, and
`note` something the platform recorded, like a handover.

## The recording

A link to the audio works for **five minutes**, so download it straight away rather than storing the
link:

**curl**

```sh
#!/bin/sh
# Get a link to a recording. The link works for five minutes, so download the audio straight away.
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/recording" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// Get a link to a recording. The link works for five minutes, so download the audio straight away.
const response = await fetch("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/recording", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Get a link to a recording. The link works for five minutes, so download the audio straight away.
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/recording",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Get a link to a recording. The link works for five minutes, so download the audio straight away.
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("GET", "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/recording", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Get a link to a recording. The link works for five minutes, so download the audio straight away.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/recording"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Get a link to a recording. The link works for five minutes, so download the audio straight away.
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/recording")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Get a link to a recording. The link works for five minutes, so download the audio straight away.
$curl = curl_init("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/recording");
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

The file is stereo Ogg: the caller on the left, the agent on the right. Each key may ask for 60
links a minute and 2,000 a day, and every link is recorded in your organization's audit log.

## What it cost

Ask for `include=cost`, which needs `billing:read` as well:

**curl**

```sh
#!/bin/sh
# Read what a conversation cost
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=cost" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// Read what a conversation cost
const response = await fetch("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=cost", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Read what a conversation cost
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
    params={
        "include": "cost",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Read what a conversation cost
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("GET", "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=cost", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Read what a conversation cost
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=cost"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Read what a conversation cost
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=cost")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Read what a conversation cost
$curl = curl_init("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d?include=cost");
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

`cost.credits` is what the conversation cost: its own charge and every analysis of it, less any
refund. A chat is charged as it goes, so an open chat's cost can still grow. Every charge behind the
number is in the [credit history](/guides/billing).

## Run the analysis again

Run the agent's analysis on a conversation that has ended: again, after you change the agent's
analysis settings, or for the first time on one that was never analysed. This needs `analysis:run`:

**curl**

```sh
#!/bin/sh
# Analyse a conversation again. It costs credit, like any analysis.
curl -sS --fail-with-body -X POST "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/analysis" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// Analyse a conversation again. It costs credit, like any analysis.
const response = await fetch("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/analysis", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Analyse a conversation again. It costs credit, like any analysis.
# pip install httpx
import os

import httpx

response = httpx.post(
    "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/analysis",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Analyse a conversation again. It costs credit, like any analysis.
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("POST", "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/analysis", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Analyse a conversation again. It costs credit, like any analysis.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/analysis"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("POST", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Analyse a conversation again. It costs credit, like any analysis.
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Post, "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/analysis")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Analyse a conversation again. It costs credit, like any analysis.
$curl = curl_init("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d/analysis");
curl_setopt_array($curl, [
    CURLOPT_POST => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
    CURLOPT_POSTFIELDS => "",
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

The answer is the conversation with its new `analysis`, and `conversation.analyzed` is sent again.
Each run costs credit, like the first one, and an organization may run 10 a minute. A conversation
still in progress is refused with `409 conversation_in_progress`, and one where too little was said
with `422 conversation_too_short`.

## Keep your copy in sync

Ask for what changed instead of reading everything again:

**curl**

```sh
#!/bin/sh
# Sync what changed. Send each page's next_cursor back as cursor= until has_more is false.
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/conversations?order=changed&changed_after=2026-10-01T00:00:00Z" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// Sync what changed. Send each page's next_cursor back as cursor= until has_more is false.
const response = await fetch("https://api.aigently.ai/v1/conversations?order=changed&changed_after=2026-10-01T00:00:00Z", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Sync what changed. Send each page's next_cursor back as cursor= until has_more is false.
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://api.aigently.ai/v1/conversations",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
    params={
        "order": "changed",
        "changed_after": "2026-10-01T00:00:00Z",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Sync what changed. Send each page's next_cursor back as cursor= until has_more is false.
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("GET", "https://api.aigently.ai/v1/conversations?order=changed&changed_after=2026-10-01T00:00:00Z", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Sync what changed. Send each page's next_cursor back as cursor= until has_more is false.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations?order=changed&changed_after=2026-10-01T00:00:00Z"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Sync what changed. Send each page's next_cursor back as cursor= until has_more is false.
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.aigently.ai/v1/conversations?order=changed&changed_after=2026-10-01T00:00:00Z")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Sync what changed. Send each page's next_cursor back as cursor= until has_more is false.
$curl = curl_init("https://api.aigently.ai/v1/conversations?order=changed&changed_after=2026-10-01T00:00:00Z");
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

With `order=changed`, the oldest change comes first. Read until `has_more` is `false`, keep the last
page's `next_cursor`, and next time start from it: you get every conversation that changed since,
once, in order. Changes from the last minute wait for a later page, so a conversation still being
written is never skipped. Every conversation has a `revision` that only goes up: of two copies,
keep the higher.

## Delete one

Deleting needs `conversations:delete`, a permission no starting point in the console includes:

**curl**

```sh
#!/bin/sh
# Delete a conversation. With its recording, for good.
curl -sS --fail-with-body -X DELETE "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// Delete a conversation. With its recording, for good.
const response = await fetch("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# Delete a conversation. With its recording, for good.
# pip install httpx
import os

import httpx

response = httpx.delete(
    "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// Delete a conversation. With its recording, for good.
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("DELETE", "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// Delete a conversation. With its recording, for good.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("DELETE", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// Delete a conversation. With its recording, for good.
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Delete, "https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// Delete a conversation. With its recording, for good.
$curl = curl_init("https://api.aigently.ai/v1/conversations/5f0c9a52-7d3e-4b1a-9c8f-6e2d4a0b3c1d");
curl_setopt_array($curl, [
    CURLOPT_CUSTOMREQUEST => "DELETE",
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

The transcript, the recording and any pictures go with it, for good. A call still in progress is
refused with `409 conversation_in_progress`: end it first. A chat that is still open is charged for
what it used, then deleted. What it cost stays in the credit history. It is listed below with the
reason `api`, `conversation.deleted` is sent to your receivers, and the organization's audit log
records which key deleted it.

## Deleted conversations

A conversation can be deleted — by the organization's retention, from the console, through this API,
or with its agent or project. Ask for those too, and remove them from your copy:

**curl**

```sh
#!/bin/sh
# List deleted conversations
curl -sS --fail-with-body -X GET "https://api.aigently.ai/v1/conversations/deleted" \
  -H "Authorization: Bearer $AIGENTLY_API_KEY"
```

**JavaScript**

```js
// List deleted conversations
const response = await fetch("https://api.aigently.ai/v1/conversations/deleted", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.AIGENTLY_API_KEY}`,
  },
});
const answer = await response.json();
if (!response.ok) throw new Error(`${answer.code}: ${answer.detail}`);
console.log(answer);
```

**Python**

```python
# List deleted conversations
# pip install httpx
import os

import httpx

response = httpx.get(
    "https://api.aigently.ai/v1/conversations/deleted",
    headers={
        "Authorization": f"Bearer {os.environ['AIGENTLY_API_KEY']}",
    },
)
if response.is_error:
    raise SystemExit(response.text)
print(response.json())
```

**Go**

```go
// List deleted conversations
package main

import (
	"fmt"
	"io"
	"net/http"
	"os"
)

func main() {
	request, err := http.NewRequest("GET", "https://api.aigently.ai/v1/conversations/deleted", nil)
	if err != nil {
		panic(err)
	}
	request.Header.Set("Authorization", "Bearer "+os.Getenv("AIGENTLY_API_KEY"))
	response, err := http.DefaultClient.Do(request)
	if err != nil {
		panic(err)
	}
	defer response.Body.Close()
	body, _ := io.ReadAll(response.Body)
	if response.StatusCode >= 400 {
		fmt.Fprintln(os.Stderr, string(body))
		os.Exit(1)
	}
	fmt.Println(string(body))
}
```

**Java**

```java
// List deleted conversations
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class Main {
    public static void main(String[] args) throws Exception {
        HttpRequest request = HttpRequest.newBuilder(URI.create("https://api.aigently.ai/v1/conversations/deleted"))
            .header("Authorization", "Bearer " + System.getenv("AIGENTLY_API_KEY"))
            .method("GET", HttpRequest.BodyPublishers.noBody())
            .build();
        // HTTP/1.1: on a plain-http address Java's default asks to upgrade, which not every
        // server allows.
        HttpClient client = HttpClient.newBuilder().version(HttpClient.Version.HTTP_1_1).build();
        HttpResponse<String> response =
            client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() >= 400) {
            System.err.println(response.body());
            System.exit(1);
        }
        System.out.println(response.body());
    }
}
```

**C#**

```csharp
// List deleted conversations
using System.Net.Http.Headers;
using System.Text;

using var client = new HttpClient();
client.DefaultRequestHeaders.Authorization =
    new AuthenticationHeaderValue("Bearer", Environment.GetEnvironmentVariable("AIGENTLY_API_KEY"));
var request = new HttpRequestMessage(HttpMethod.Get, "https://api.aigently.ai/v1/conversations/deleted")
{
};
var response = await client.SendAsync(request);
var body = await response.Content.ReadAsStringAsync();
if (!response.IsSuccessStatusCode)
{
    Console.Error.WriteLine(body);
    return 1;
}
Console.WriteLine(body);
return 0;
```

**PHP**

```php
<?php
// List deleted conversations
$curl = curl_init("https://api.aigently.ai/v1/conversations/deleted");
curl_setopt_array($curl, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER => [
        "Authorization: Bearer " . getenv("AIGENTLY_API_KEY"),
    ],
]);
$body = curl_exec($curl);
if (curl_getinfo($curl, CURLINFO_RESPONSE_CODE) >= 400) {
    fwrite(STDERR, $body . "\n");
    exit(1);
}
echo $body, "\n";
```

Deletions are listed for 30 days.

## What a test key sees

A test key reads, searches and deletes only conversations made with test keys, and a live key never
sees them. A real conversation asked for with a test key is `404`, as if it did not exist. Running
the analysis again on a test call gives its sample analysis again, at no cost; a test chat is
analysed by the agent's real model, and charged.
