# Search and filter with the API and SDK

> Filter, search, and sort entries, compositions, patterns, and assets with the content API clients and the Uniform REST API.

Source: https://docs.uniform.app/docs/sdk/content-api-clients/search-and-filter

The `list` methods of the [Content API clients](https://docs.uniform.app/docs/sdk/content-api-clients) and the `AssetClient` accept filters, a keyword search, and a sort order. They use the same search index as the [search and filter bar](https://docs.uniform.app/docs/guides/content-organization/search-filter-sort) in the Uniform dashboard. What you can find in a listing, you can also find from code. The API supports a few filters the bar doesn't, such as asset and link fields and their sub-properties.

## Choosing a client

Patterns don't have their own endpoints. You list them with the entry or composition clients and the `pattern` and `patternType` options.

| Content | Client and method | Options | Endpoint |
| --- | --- | --- | --- |
| Entries | `EntryDeliveryClient.list`, `EntryManagementClient.list` | `pattern: false` (default) | `/api/v1/entries` |
| Entry patterns | `EntryDeliveryClient.list`, `EntryManagementClient.list` | `pattern: true` | `/api/v1/entries` |
| Compositions | `CompositionDeliveryClient.list`, `CompositionManagementClient.list` | `pattern: false` | `/api/v1/canvas` |
| Composition patterns | `CompositionDeliveryClient.list`, `CompositionManagementClient.list` | `pattern: true, patternType: 'composition'` | `/api/v1/canvas` |
| Component patterns | `CompositionDeliveryClient.list`, `CompositionManagementClient.list` | `pattern: true, patternType: 'component'` | `/api/v1/canvas` |
| Assets | `AssetClient.list` from `@uniformdev/assets` | none | `/api/v1/assets` |

`CompositionDeliveryClient` calls the edge counterpart, `/api/v1/compositions`, which forwards filters to `/api/v1/canvas`. The composition clients return compositions and patterns together when you omit `pattern`. The entry clients return only regular entries unless you set `pattern: true` or `pattern: 'any'`.

Delivery clients read from the edge and default to published content. Management clients read from the origin and default to draft content. Both accept the same filters, and you can set `state` to choose draft or published. Assets are available only through the management API. They're returned in their published state and have no locales or editions.

## Filter syntax

Pass filters as an object. Each key is a field, and each value is an object with one operator and its value:

```ts
import { EntryDeliveryClient } from '@uniformdev/canvas'

const entries = new EntryDeliveryClient({ apiKey, projectId })

const { entries: results } = await entries.list({
  filters: {
    type: { eq: 'article' },
    'fields.brandName': { match: 'adidas' },
  },
})
```

To apply two operators to the same field, put the operator in the key instead:

```ts
const { entries: results } = await entries.list({
  filters: {
    type: { eq: 'product' },
    'fields.price[gte]': 50,
    'fields.price[lte]': 500,
  },
})
```

The client serializes filters into `filters.<field>[<operator>]=<value>` query parameters. List values are joined with commas. You can call the REST API directly with the same syntax. Send the request to the Uniform API host for your region, with an API key in the `x-api-key` header:

```text
GET /api/v1/entries?projectId=<projectId>&filters.type[eq]=product&filters.fields.price[gte]=50&filters.fields.price[lte]=500
x-api-key: <API_KEY>
```

An entry, composition, or asset must match every filter to be returned.

### Operators

| Operator | Matches | UI equivalent |
| --- | --- | --- |
| `eq` / `neq` | Exact equality / inequality | `is` / `is not` |
| `match` | Contains the text. Text-like fields only. | `contains` |
| `starts` | Starts with the text. The value can contain only letters, numbers, `_`, `.`, `-`, and spaces. | `starts with` |
| `lt` / `lte` / `gt` / `gte` | Less than / less than or equal to / greater than / greater than or equal to. Number, date, and date/time fields, including `created` and `modified`. | `is before`, `is after`, `less than`, `greater than`, and similar |
| `in` / `nin` | Any of / none of a list of values | `is any of` / `is none of` |
| `all` | List-valued fields, such as `labels` and multi-select fields, contain every value in the list | `is all of` |
| `def` | `true` if the field has a value, `false` if it doesn't | `is not empty` / `is empty` |

The API has no `between` operator. Combine `gte` and `lte` on the same field instead. Dates accept `YYYY-MM-DD` or a full ISO 8601 date and time. An empty value is rejected, so use `def: false` to find items without a value.

Not every operator works on every field. An unsupported operator, an unknown field, or a malformed key returns HTTP 400. For an unsupported operator, the message lists the operators the field supports.

## System fields

System fields apply to every item, regardless of its type.

| Field | Operators | Available on |
| --- | --- | --- |
| `entityId` | `eq`, `neq`, `in`, `nin` | All |
| `type` | `eq`, `neq`, `in`, `nin` | All. The content type, composition type, component type, or asset type. |
| `name`, `slug` | `match`, `starts`, `eq`, `neq`, `in`, `nin`, `def` | All. Assets have `name` only. |
| `created`, `modified` | `eq`, `neq`, `lt`, `lte`, `gt`, `gte`, `in`, `nin` | All |
| `creator`, `author` | `match`, `starts`, `eq`, `neq`, `in`, `nin` | All. The name of the user who created or last modified the item. |
| `creatorSubject`, `authorSubject` | `eq`, `neq`, `in`, `nin` | All. The user ID of the creator or last modifier. |
| `categoryId` | `eq`, `neq`, `in`, `nin`, `def` | Compositions and patterns |
| `labels`, `labelGroups` | `eq`, `neq`, `in`, `nin`, `all`, `def` | Assets |
| `uiStatus` | `eq`, `neq`, `in`, `nin` | Entries, compositions, and patterns. Values: `draft`, `modified`, `published`. |
| `locale` | `eq`, `neq`, `in`, `nin` | Entries, compositions, and patterns. Matches items that have the locale enabled. |
| `workflowId`, `workflowStageId` | `eq`, `neq`, `in`, `nin`, `def` | Entries, compositions, and patterns |
| `patternId` | `eq`, `neq`, `in`, `nin`, `def` | Entries, compositions, and patterns |
| `editionId`, `releaseId` | `eq`, `neq`, `in`, `nin`, `def` | Entries, compositions, and patterns |
| `projectMapId`, `projectMapNodeId` | `eq`, `neq`, `in`, `nin`, `def` | Compositions and patterns |

`type`, `uiStatus`, and `locale` can each be used only once per request.

## Field and parameter filters

Address custom fields with a prefix:

- Entries and entry patterns: `fields.<fieldId>`
- Compositions and composition or component patterns: `parameters.<parameterId>`. Only the root component's parameters are matched.
- Assets: `fields.<fieldId>`

Entries, compositions, and patterns need a filter to a single type before you can filter or sort by a field, for example `type: { eq: 'article' }`. Without one, the API returns HTTP 400. Asset filters don't have this requirement, unless the same field ID has different types across asset types. Sorting by an asset field still needs a filter to a single asset type.

| Field type | Operators |
| --- | --- |
| Text, single select | `match`, `starts`, `eq`, `neq`, `in`, `nin`, `def` |
| Multi select | `eq`, `neq`, `in`, `nin`, `all`, `def` |
| Rich text | `match`, `starts`, `def` |
| Number, date, date/time | `eq`, `neq`, `lt`, `lte`, `gt`, `gte`, `in`, `nin`, `def` |
| Boolean | `eq`, `neq`, `def` |
| Reference (entries only), by referenced entry ID | `eq`, `neq`, `in`, `nin`, `def` |
| Asset, by asset ID | `eq`, `neq`, `in`, `nin`, `def` |
| Link, by path | `match`, `starts`, `eq`, `neq`, `in`, `nin`, `def` |

Blocks, enrichment, JSON data, and image URL fields can't be filtered.

### Reference, asset, and link sub-properties

Reference fields on entries, and asset and link fields, can also be filtered by a system property of the item they point to. For example, filter a reference field by the referenced entry's name or slug. Add the property to the field path:

| Field type | Sub-property | Operators |
| --- | --- | --- |
| Reference | `.name`, `.slug` | `match`, `starts`, `eq`, `neq`, `in`, `nin`, `def` |
| Reference | `.type`, `.uiStatus` | `eq`, `neq`, `in`, `nin`, `def` |
| Asset | `.url`, `.title`, `.description` | `match`, `starts`, `eq`, `neq`, `in`, `nin`, `def` |
| Asset | `.mediaType` | `eq`, `neq`, `in`, `nin`, `def` |
| Link | `.type`, `.projectMapNodeId` | `eq`, `neq`, `in`, `nin`, `def` |

```ts
const { entries: sessions } = await entries.list({
  filters: {
    type: { eq: 'eventSession' },
    'fields.speaker.slug': { eq: 'jane-doe' },
  },
})
```

You can't filter by the custom fields of a referenced entry, or through more than one level of references.

### Asset properties

Every asset has these filterable properties in addition to the fields of its asset type:

| Property | Type |
| --- | --- |
| `fields.title`, `fields.description`, `fields.url`, `fields.mediaType` | Text |
| `fields.size` (bytes), `fields.width`, `fields.height` (pixels) | Number |

## Keyword search

Pass `search` to run a full-text search. It matches the name, slug, and ID of an item and the values of its text-like fields. This includes content from resolved patterns and [connected external data](https://docs.uniform.app/docs/guides/content-organization/search-filter-sort#search-and-filter-on-connected-external-data). Search tolerates small typos. The tail of very long text values isn't guaranteed to be searchable.

```ts
const { entries: results } = await entries.list({
  search: 'summer sale',
  filters: { type: { eq: 'article' } },
  orderBy: ['relevance_DESC'],
})
```

Combine `search` with filters to narrow the results. Sort by `relevance_DESC` to return the best matches first.

On assets, use `keyword` instead of `search`. It runs the same full-text search against the asset's title and description.

> **Note:**
>
> The entry and composition endpoints also accept `keyword`, an older match that doesn't use the search index. On compositions it matches only the name, slug, and type. Use `search` for new code.

## Sorting

Pass one sort field in `orderBy`, formatted as `<field>_ASC` or `<field>_DESC`:

- `created_at`, `updated_at`, `name`, `slug`
- `creator`, `author`
- A field or parameter of a single selected type, for example `fields.price_ASC`. Rich text and multi-select fields can't be sorted on.
- `relevance`, while `search` is set
- On assets filtered to a single asset type, also `fields.size`, `fields.width`, and `fields.height`

The default order is `updated_at_DESC` for entries, `name_ASC` for compositions and patterns, and `created_at_ASC` for assets. Passing more than one sort field returns HTTP 400.

## Pagination and total count

Use `limit` and `offset` to page through results, and `withTotalCount: true` to get the total number of matches in `totalCount`. When a request uses `search`, filters, or a sort on anything other than name, slug, or dates, `limit` can be at most 100.

## Locales and editions

The `locale` option controls which locale the results are resolved to and which locale's field values filters and search match. It also limits results to items that enable that locale or enable no locales. Without `locale`, filters and search match values in any locale.

The `locale` filter works differently: `filters: { locale: { eq: 'de-DE' } }` returns items that have that locale enabled.

On entries and compositions, `editions: 'auto'` (the default) returns the best-matching [edition](https://docs.uniform.app/docs/guides/composition/editions) of each item for the requested locale. `editions: 'all'` returns every edition as its own result.

## Examples

### Compositions by parameter value

```ts
import { CompositionDeliveryClient } from '@uniformdev/canvas'

const compositions = new CompositionDeliveryClient({ apiKey, projectId })

const { compositions: pages } = await compositions.list({
  pattern: false,
  filters: {
    type: { eq: 'landingPage' },
    'parameters.audience': { in: ['b2b', 'b2c'] },
  },
  orderBy: ['updated_at_DESC'],
})
```

### Component patterns modified this year

```ts
import { CompositionManagementClient } from '@uniformdev/canvas'

const compositions = new CompositionManagementClient({ apiKey, projectId })

const { compositions: patterns } = await compositions.list({
  pattern: true,
  patternType: 'component',
  filters: {
    type: { eq: 'hero' },
    modified: { gte: '2026-01-01' },
  },
})
```

### Assets

```ts
import { AssetClient } from '@uniformdev/assets'

const assets = new AssetClient({ apiKey, projectId })

const { assets: images } = await assets.list({
  keyword: 'hero',
  filters: {
    type: { eq: 'image' },
    'fields.width': { gte: 1920 },
    labels: { all: ['approved', 'featured'] },
  },
  orderBy: ['fields.size_DESC'],
})
```

Label filters take label public IDs.

## Limitations

- Filters are always combined with `AND`. There is no `OR` across fields. To match several values of one field, use `in`.
- Composition and pattern filters match root component parameters only, and entry filters can't reach fields inside blocks.
- Exact-match filter values can be at most 255 characters. Text is indexed up to about 10,000 characters per field.
- Search, filters, and custom sorting aren't available for items in [Trash](https://docs.uniform.app/docs/guides/content-organization/trash). Combining them with `deleted: 'only'` or `deleted: 'include'` returns HTTP 400.

## Related

- [Search, filter, and sort](https://docs.uniform.app/docs/guides/content-organization/search-filter-sort): the search and filter bar in the Uniform dashboard
- [Content API clients](https://docs.uniform.app/docs/sdk/content-api-clients): the delivery and management clients
- _For the US region:_

  _For the EU region:_
