> ## 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.

# Labels and lists over the API

> Sort, filter and page agents and workflows, select every match, and manage labels from the API.

Everything the list pages do is available over the API: sorted and filtered listing with a total count, collecting every matching id, bulk labelling, and label key administration.

Pass your credential in the `Authorization` header. A personal access token (`pat_`) also needs the `X-Anyreach-Org` header. See [Authentication](/api-reference/authentication).

```bash theme={null}
export ANYREACH_TOKEN=...
export ANYREACH_ORG_ID=...
```

## List agents and workflows

`GET /core/agents` and `GET /workflow/workflows` each have two modes.

| Mode | Selected by | Behaviour |
| - | - | - |
| **Sorted listing** | `offset`, or any of `sort`, `dir`, `search`, `labels` and the filters below | Sorts and filters on the server, pages by `offset` and `limit`, and returns the total match count on the first page. |
| **Original listing** | Only the original parameters, such as `name`, `limit` and the `created_*` and `updated_*` ranges, or any `cursor` or `ids` | Newest first, paged by `cursor`. Unchanged, so existing integrations keep working. |

<Note>
  A `cursor` can't be combined with `sort` or `offset`. The request is rejected with `400`.
</Note>

### Sorting

| Parameter | Agents | Workflows |
| - | - | - |
| `sort` | `name`, `created_at`, `updated_at`, `created_by`, `modified_by`, `total_conversations`, `last_activity`, `deployed`, or `label:<key>` | `name`, `created_at`, `updated_at`, `created_by`, `modified_by`, `total_runs`, `last_run`, `live`, `published`, or `label:<key>` |
| `dir` | `asc` or `desc`. Defaults to `desc`. | Same |

The default sort is `created_at`, newest first. Rows with no value sort last in either direction. Every sort ends with the id, so pages never overlap or skip a row.

### Filters

| Parameter | Agents | Workflows |
| - | - | - |
| `search` | Name, company name, or phone number digits (four or more) | Name |
| `labels` | Label filter, see below | Same |
| `created_by`, `modified_by` | Actor, such as `user:<id>` | Same |
| `created_after`, `created_before`, `updated_after`, `updated_before` | ISO 8601 date-time | Same |
| Activity range | `last_activity_after`, `last_activity_before` | `last_run_after`, `last_run_before` |
| Status | `deployed` (boolean), `channels` (comma-separated `voice`, `chat`, `demo`; matches agents with all of them) | `live`, `published`, `has_trigger` (booleans), `trigger_status` (comma-separated `active`, `testing`, `inactive`) |

The `labels` parameter is a URL-encoded JSON object. Each key maps to a value, a list of values, or `null`:

```json theme={null}
{ "industry": ["Healthcare", "Financial"], "region": "EMEA", "client": null }
```

This matches entities whose industry is Healthcare **or** Financial, **and** whose region is EMEA, **and** that have no client label. Values are trimmed, and a key accepts up to 50 values.

### Paging and the total

| | Agents | Workflows |
| - | - | - |
| `limit` | 1 to 1,000. Defaults to 100. | 1 to 100. Defaults to 20. |
| `offset` | Rows to skip. Defaults to 0. | Same |
| Response | A JSON array of agents | `data` plus `pagination` |
| Total match count | `X-Total-Count` header on the `offset=0` page | `X-Total-Count` header and `pagination.total` on the `offset=0` page |
| Next page | Add `limit` to `offset`; stop when a page returns fewer than `limit` rows | `pagination.offset`, which is `null` on the last page |

The total is counted only on the first page, so request `offset=0` first when you need it.

```bash theme={null}
curl -G https://api.anyreach.ai/core/agents \
  -H "Authorization: Bearer $ANYREACH_TOKEN" \
  -H "X-Anyreach-Org: $ANYREACH_ORG_ID" \
  --data-urlencode 'sort=last_activity' \
  --data-urlencode 'dir=desc' \
  --data-urlencode 'labels={"industry":["Healthcare"]}' \
  --data-urlencode 'offset=0' \
  --data-urlencode 'limit=50' \
  -D -
```

Each agent and workflow in the response carries a `labels` object:

```json theme={null}
{ "industry": "Healthcare", "language": ["English", "Spanish"] }
```

A key with several values holds a list. Any other key holds a string.

## Collect every matching id

To act on everything a filter matches, page through the ids instead of the full rows:

| Endpoint | Returns |
| - | - |
| `GET /core/agents/ids` | `{ "ids": [...], "total": N }` |
| `GET /workflow/workflows/ids` | Same |

They take the same `search`, `sort`, `dir`, `labels` and filter parameters as the lists, plus `offset` and `limit` (up to 1,000, the default). Ids come back in list order. Page until you have `total` ids. A page past the end is empty, with the current total.

## Label many entities at once

`PATCH /core/agents/labels` and `PATCH /workflow/workflows/labels` apply one change to up to 500 entities:

```bash theme={null}
curl -X PATCH https://api.anyreach.ai/core/agents/labels \
  -H "Authorization: Bearer $ANYREACH_TOKEN" \
  -H "X-Anyreach-Org: $ANYREACH_ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["9b2c...", "41fe..."],
    "set": { "industry": "Healthcare" },
    "add": { "language": ["Spanish"] },
    "remove": { "language": ["French"] },
    "clear": ["pilot"]
  }'
```

| Field | Effect |
| - | - |
| `ids` | Required. 1 to 500 agent or workflow ids. |
| `set` | Replaces a key's value. Use a string, or a list for a key with several values. |
| `add` | Adds values to a key with several values, keeping the ones already there. |
| `remove` | Removes values. A list emptied by the removal drops the key. |
| `clear` | Removes keys entirely. |

At least one of `set`, `add`, `remove` or `clear` is required. They apply in the order clear, set, add, remove. The response is `{ "updated": N }`, the number of entities whose labels changed.

Labelling agents needs `agents:manage`; labelling workflows needs `workflows:manage`. A value that the key doesn't allow, or an unknown key, is rejected with `400` and nothing changes.

## Manage label keys

Label keys live under `/core/label-keys`. Reading them needs read access to agents or workflows; every change needs `agents:manage`.

| Method | Path | Description |
| - | - | - |
| `GET` | `/core/label-keys` | List the organization's keys with `agent_count` and `workflow_count`. Pass `in_use_for=agent` or `in_use_for=workflow` for only the keys in use there. |
| `POST` | `/core/label-keys` | Create a key. Body: `key`, `name`, optional `values` (a list, or `null` for any value) and `multi`. |
| `PATCH` | `/core/label-keys/{key_id}` | Change `name`, `values` or `multi`. |
| `POST` | `/core/label-keys/{key_id}/values` | Add one value to a key's allowed list. Body: `value`. |
| `GET` | `/core/label-keys/{key_id}/values` | Each value with how many agents and workflows use it, including allowed values nobody uses yet. |
| `POST` | `/core/label-keys/{key_id}/rename-value` | Rename a value everywhere, or remove it with `to: null`. Body: `from`, `to`. Renaming onto an existing value merges the two. Returns counts of changed agents, workflows and saved views. |
| `DELETE` | `/core/label-keys/{key_id}` | Delete the key and strip it from every agent, workflow and saved view. Returns the same counts. |

### Removing values that are in use

A `PATCH` whose `values` list drops a value some agent or workflow still uses is refused with `409`, and nothing changes:

```json theme={null}
{
  "detail": {
    "message": "These values are in use and the new list no longer allows them",
    "values": ["Healthcare"]
  }
}
```

Repeat the request with `?force=true` to remove those values from every agent, workflow and saved view and save the new list. The whole edit happens in one transaction: it applies completely or not at all, and a label write arriving at the same moment waits for it.

### Other errors

| Status | When |
| - | - |
| `400` | An unknown key, a value the key doesn't allow, or a malformed list parameter such as `labels` |
| `404` | The key doesn't exist in your organization |
| `409` | Another label already uses the key, the organization already has 20 keys, a key already lists 100 values, or `multi` changes while the key is in use |
| `422` | A request body that fails validation, such as a value that is empty once trimmed or longer than 64 characters |


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