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

# Search and filters

> Find conversations by caller, agent, channel, campaign, duration, and more.

Narrow the conversation list to the calls and chats you care about. Filters are applied server-side by `GET /core/conversations`, mirrored to the URL so you can share a filtered view, and persisted to your browser per organization so they survive a reload.

Open the filter dialog from the inbox toolbar, set any combination of fields, and choose **Apply**. Choose **Reset** to clear every field back to its default.

## UI filters

These fields are available in the filter dialog. Each maps to a query parameter on `GET /core/conversations`.

| Filter                               | Parameter                           | Match                                | Notes                                                                                                                                     |
| ------------------------------------ | ----------------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------- |
| **Caller (Phone Number or User ID)** | `user_id`                           | `ILIKE` (case-insensitive substring) | Matches the caller's phone number or user identifier. Partial values work.                                                                |
| **Agent**                            | `agent_id`                          | Exact equality                       | Pick an agent from the searchable list; the dialog stores its ID.                                                                         |
| **Direction**                        | `direction`                         | Exact equality                       | `inbound` or `outbound`. **All** clears the filter.                                                                                       |
| **Status**                           | `status`                            | Exact equality                       | One of `triggered`, `ringing`, `in_progress`, `completed`, `failed`, `cancelled`, `transferred`, `unanswered`. **All** clears the filter. |
| **Channel**                          | `channel`                           | Exact equality                       | `telephone`, `webrtc`, `email`, or `text`. **All** clears the filter.                                                                     |
| **Campaign**                         | `custom_metadata.anyreach_campaign` | JSON contains                        | Type a campaign name; it is matched against the `anyreach_campaign` key in the conversation's custom metadata.                            |
| **Min Duration (seconds)**           | `duration_above`                    | `>=`                                 | Lower bound on call/chat `duration`.                                                                                                      |
| **Max Duration (seconds)**           | `duration_below`                    | `<=`                                 | Upper bound on `duration`.                                                                                                                |
| **Min User Turns**                   | `user_turn_count_above`             | `>=`                                 | Lower bound on the number of user turns.                                                                                                  |
| **Max User Turns**                   | `user_turn_count_below`             | `<=`                                 | Upper bound on the number of user turns.                                                                                                  |
| **Created After**                    | `created_after`                     | `>=` on `created_at`                 | Datetime lower bound.                                                                                                                     |
| **Created Before**                   | `created_before`                    | `<=` on `created_at`                 | Datetime upper bound.                                                                                                                     |

<Note>
  The **Caller** field maps to `user_id` and uses substring matching, so a partial number or ID returns every conversation that contains it. The agent, direction, status, and channel filters match exactly.
</Note>

## Server-only parameters

`GET /core/conversations` accepts several filters that the dialog does not surface. Send them directly to the API when you need finer control.

| Parameter          | Match                | Description                                                                                                                                   |
| ------------------ | -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| `agent_number`     | `ILIKE`              | Substring match on the phone number the agent answered or dialed from.                                                                        |
| `agent_version_id` | Exact equality       | Restrict to a specific published agent version.                                                                                               |
| `web_widget_id`    | Exact equality       | Restrict to a specific web chat widget.                                                                                                       |
| `trunk_id`         | Exact equality       | Restrict to conversations on a specific SIP trunk.                                                                                            |
| `service_version`  | `ILIKE`              | Substring match on the platform service version that handled the conversation.                                                                |
| `custom_metadata`  | JSON contains        | A JSON object string; every key/value is matched against the conversation's `custom_metadata`. The campaign filter is a special case of this. |
| `updated_after`    | `>=` on `updated_at` | Datetime lower bound on last update.                                                                                                          |
| `updated_before`   | `<=` on `updated_at` | Datetime upper bound on last update.                                                                                                          |

<Info>
  `custom_metadata` must be a URL-encoded JSON object. Invalid JSON returns `400 Invalid JSON format for custom_metadata`, and a non-object value returns `400 custom_metadata must be a JSON object`.
</Info>

### Example

```bash theme={null}
curl -G "https://api.anyreach.ai/core/conversations" \
  -H "Authorization: Bearer ak_..." \
  --data-urlencode "channel=telephone" \
  --data-urlencode "direction=inbound" \
  --data-urlencode "duration_above=60" \
  --data-urlencode 'custom_metadata={"anyreach_campaign":"spring-outreach"}'
```

The endpoint requires one of the scopes `conversations:read`, `conversations:read_sensitive`, or `conversations:manage`. User personal access tokens (`pat_`) must also send `X-Anyreach-Org: <organization_id>`; org API keys (`ak_`) carry their organization implicitly.

## Match semantics

All active filters are combined with AND — a conversation must satisfy every set filter to appear.

| Filter type                                                                                   | Operator                                   |
| --------------------------------------------------------------------------------------------- | ------------------------------------------ |
| `user_id`, `agent_number`, `service_version`                                                  | Case-insensitive substring (`ILIKE`)       |
| `agent_id`, `agent_version_id`, `web_widget_id`, `trunk_id`, `direction`, `channel`, `status` | Exact equality                             |
| `duration_above`/`below`, `user_turn_count_above`/`below`                                     | `>=` / `<=` range bounds                   |
| `created_after`/`before`, `updated_after`/`before`                                            | `>=` / `<=` on `created_at` / `updated_at` |
| `custom_metadata` (including campaign)                                                        | JSON object containment                    |

## Persistence and deep-linking

Filters live in three places, in priority order:

```
URL query params  ─►  applied state  ─►  localStorage (per org)
   (highest)                                 (fallback)
```

<Steps>
  <Step title="URL params take precedence">
    On load, the page reads filter values from the URL query string. If any filter param is present, those values win and saved filters are ignored for that load.
  </Step>

  <Step title="localStorage fallback">
    When the URL has no filter params, the page restores the last applied filters from `localStorage` under the key `filters:conversations:<orgSlug>`. Saved filters are scoped per organization, so each org keeps its own view.
  </Step>

  <Step title="Changes are mirrored back">
    Whenever filters change, the page rewrites the URL with the active params (without adding a history entry) and re-saves them to `localStorage`. Clearing all filters removes the saved entry.
  </Step>
</Steps>

### Deep-link parameters

Link directly to a filtered inbox by adding query params to the conversations URL. These params are honored on load:

`caller`, `agent_id`, `direction`, `status`, `campaign`, `created_after`, `created_before`, `duration_above`, `duration_below`, `user_turn_count_above`, `user_turn_count_below`.

<Note>
  In the browser URL, the caller filter appears as `caller` and the campaign filter appears as `campaign` (it is expanded to `custom_metadata.anyreach_campaign` when the API is called). Both map to `user_id` and `custom_metadata` respectively on the backend.
</Note>

For example, link to every inbound call from a campaign:

```
/<orgSlug>/conversations?direction=inbound&campaign=spring-outreach
```

## Related

<CardGroup cols={2}>
  <Card title="Inbox overview" icon="inbox" href="/conversations/inbox-overview">
    How the conversation list is laid out and what each column shows.
  </Card>

  <Card title="Exporting conversations" icon="file-export" href="/conversations/exporting-conversations">
    Export the current filtered view to CSV.
  </Card>
</CardGroup>
