# List for agent

Returns conversations (jobs) for a specific agent, filtered and paginated.





Returns conversations (jobs) for a specific agent, filtered and paginated.

```http
GET /api/public/v1/agents/{agent_id}/conversations
```

<Callout type="info">
  `agent_id` accepts either the ULID (`cci_...`) or the human-readable agent slug. Agent slugs may contain `/` (for example `presmihaylov/claudecontrol`) — these are accepted in the path either raw or URL-encoded as `%2F`.
</Callout>

## Query parameters [#query-parameters]

<TypeTable
  type="{
  status: {
    type: &#x22;csv&#x22;,
    description: &#x22;Restrict to one or more of `active`, `completed`, `error`, `abandoned`. Case-sensitive. Empty CSV segments are rejected.&#x22;
  },
  updated_after: {
    type: &#x22;RFC3339 timestamp&#x22;,
    description: &#x22;Return only conversations whose `updated_at` is **strictly after** the given timestamp.&#x22;
  },
  sort: {
    type: &#x22;string&#x22;,
    default: &#x22;created_at_desc&#x22;,
    description: &#x22;One of `created_at_asc`, `created_at_desc`, `updated_at_asc`, or `updated_at_desc`.&#x22;
  },
  limit: {
    type: &#x22;integer&#x22;,
    default: &#x22;50&#x22;,
    description: &#x22;Page size. Must be between `1` and `100` (inclusive). Values `≤ 0` or `> 100` return `400`.&#x22;
  },
  offset: {
    type: &#x22;integer&#x22;,
    default: &#x22;0&#x22;,
    description: &#x22;Pagination offset. Must be non-negative.&#x22;
  }
}"
/>

## Example [#example]

<Tabs items="[&#x22;bash&#x22;, &#x22;TypeScript&#x22;, &#x22;Ruby&#x22;, &#x22;Python&#x22;, &#x22;Go&#x22;]">
  <Tab value="bash">
    ```bash
    curl -X GET "https://api.nairi.ai/api/public/v1/agents/AGENT_ID/conversations?status=completed,active&sort=updated_at_asc&limit=100" \
      -H "Authorization: Bearer $NAIRI_API_KEY"
    ```
  </Tab>

  <Tab value="TypeScript">
    ```ts
    const url = new URL(
      `https://api.nairi.ai/api/public/v1/agents/${agentId}/conversations`,
    );
    url.searchParams.set("status", "completed,active");
    url.searchParams.set("sort", "updated_at_asc");
    url.searchParams.set("limit", "100");

    const res = await fetch(url, {
      headers: {
        Authorization: `Bearer ${process.env.NAIRI_API_KEY}`,
      },
    });
    const data = (await res.json()) as {
      conversations: Array<{ id: string; status: string; updated_at: string }>;
    };
    ```
  </Tab>

  <Tab value="Ruby">
    ```ruby
    require "net/http"
    require "json"
    require "uri"

    uri = URI("https://api.nairi.ai/api/public/v1/agents/#{agent_id}/conversations")
    uri.query = URI.encode_www_form(
      status: "completed,active",
      sort: "updated_at_asc",
      limit: 100,
    )
    req = Net::HTTP::Get.new(uri)
    req["Authorization"] = "Bearer #{ENV['NAIRI_API_KEY']}"

    res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |h| h.request(req) }
    data = JSON.parse(res.body)
    ```
  </Tab>

  <Tab value="Python">
    ```python
    import os
    import requests

    res = requests.get(
        f"https://api.nairi.ai/api/public/v1/agents/{agent_id}/conversations",
        headers={"Authorization": f"Bearer {os.environ['NAIRI_API_KEY']}"},
        params={
            "status": "completed,active",
            "sort": "updated_at_asc",
            "limit": 100,
        },
    )
    data = res.json()
    ```
  </Tab>

  <Tab value="Go">
    ```go
    package main

    import (
    	"encoding/json"
    	"fmt"
    	"io"
    	"net/http"
    	"net/url"
    	"os"
    )

    func main() {
    	agentID := os.Getenv("AGENT_ID")
    	params := url.Values{}
    	params.Set("status", "completed,active")
    	params.Set("sort", "updated_at_asc")
    	params.Set("limit", "100")

    	req, _ := http.NewRequest(
    		"GET",
    		"https://api.nairi.ai/api/public/v1/agents/"+agentID+"/conversations?"+params.Encode(),
    		nil,
    	)
    	req.Header.Set("Authorization", "Bearer "+os.Getenv("NAIRI_API_KEY"))
    	res, _ := http.DefaultClient.Do(req)
    	defer res.Body.Close()
    	raw, _ := io.ReadAll(res.Body)
    	var data map[string]any
    	json.Unmarshal(raw, &data)
    	fmt.Println(data)
    }
    ```
  </Tab>
</Tabs>

## Response [#response]

```json
{
  "conversations": [
    {
      "id": "job_01KRK1V46BXS73CSNK2VR35NPJ",
      "agent_id": "my-agent",
      "title": "Task description",
      "status": "completed",
      "created_at": "2026-04-12T18:45:12.000Z",
      "updated_at": "2026-04-12T18:47:03.000Z"
    }
  ]
}
```

The `id` field is the job ID. Pass it to [List messages](/api/conversations/list-messages) to fetch the message history. Older jobs may use the `j_` prefix instead of `job_`. Treat both as valid.

## Incremental sync pattern [#incremental-sync-pattern]

To stream new and updated conversations into your own database, persist the maximum `updated_at` you have seen so far. On each subsequent run pass it back as `updated_after` and sort ascending. Page with `offset` until you receive fewer than `limit` rows.

```text
GET /api/public/v1/agents/AGENT_ID/conversations
    ?sort=updated_at_asc
    &updated_after=<last_run_max_updated_at>
    &limit=100
```

Because `updated_after` is *strictly after*, this pattern will never return the same row twice across runs and will not miss rows updated in the meantime.

## Conversation statuses [#conversation-statuses]

| Status      | Description                           |
| ----------- | ------------------------------------- |
| `active`    | Conversation is currently in progress |
| `completed` | Conversation finished successfully    |
| `error`     | Conversation encountered an error     |
| `abandoned` | Conversation was abandoned            |

## Error responses [#error-responses]

| HTTP  | Body                                                                     | When                                                                             |
| ----- | ------------------------------------------------------------------------ | -------------------------------------------------------------------------------- |
| `400` | `{"error":"invalid status parameter: ..."}`                              | `status` contains a value other than the four allowed (or an empty CSV segment). |
| `400` | `{"error":"invalid updated_after parameter: must be RFC3339 timestamp"}` | `updated_after` is not a valid RFC3339 timestamp.                                |
| `400` | `{"error":"invalid sort parameter: ..."}`                                | `sort` is not one of the four allowed values.                                    |
| `400` | `{"error":"invalid limit parameter"}`                                    | `limit` is not a valid integer, or is `≤ 0`.                                     |
| `400` | `{"error":"invalid offset parameter"}` / `"... must be non-negative"`    | `offset` is not a valid non-negative integer.                                    |
| `400` | `{"error":"limit exceeds maximum of 100"}`                               | `limit` is greater than 100.                                                     |
| `404` | `{"error":"agent not found"}`                                            | The agent identified by `AGENT_ID` does not exist in the calling organization.   |
