Search and filter

The list methods of the 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 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.

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

ContentClient and methodOptionsEndpoint
EntriesEntryDeliveryClient.list, EntryManagementClient.listpattern: false (default)/api/v1/entries
Entry patternsEntryDeliveryClient.list, EntryManagementClient.listpattern: true/api/v1/entries
CompositionsCompositionDeliveryClient.list, CompositionManagementClient.listpattern: false/api/v1/canvas
Composition patternsCompositionDeliveryClient.list, CompositionManagementClient.listpattern: true, patternType: 'composition'/api/v1/canvas
Component patternsCompositionDeliveryClient.list, CompositionManagementClient.listpattern: true, patternType: 'component'/api/v1/canvas
AssetsAssetClient.list from @uniformdev/assetsnone/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.

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

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:

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:

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.

OperatorMatchesUI equivalent
eq / neqExact equality / inequalityis / is not
matchContains the text. Text-like fields only.contains
startsStarts with the text. The value can contain only letters, numbers, _, ., -, and spaces.starts with
lt / lte / gt / gteLess 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 / ninAny of / none of a list of valuesis any of / is none of
allList-valued fields, such as labels and multi-select fields, contain every value in the listis all of
deftrue if the field has a value, false if it doesn'tis 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 apply to every item, regardless of its type.

FieldOperatorsAvailable on
entityIdeq, neq, in, ninAll
typeeq, neq, in, ninAll. The content type, composition type, component type, or asset type.
name, slugmatch, starts, eq, neq, in, nin, defAll. Assets have name only.
created, modifiedeq, neq, lt, lte, gt, gte, in, ninAll
creator, authormatch, starts, eq, neq, in, ninAll. The name of the user who created or last modified the item.
creatorSubject, authorSubjecteq, neq, in, ninAll. The user ID of the creator or last modifier.
categoryIdeq, neq, in, nin, defCompositions and patterns
labels, labelGroupseq, neq, in, nin, all, defAssets
uiStatuseq, neq, in, ninEntries, compositions, and patterns. Values: draft, modified, published.
localeeq, neq, in, ninEntries, compositions, and patterns. Matches items that have the locale enabled.
workflowId, workflowStageIdeq, neq, in, nin, defEntries, compositions, and patterns
patternIdeq, neq, in, nin, defEntries, compositions, and patterns
editionId, releaseIdeq, neq, in, nin, defEntries, compositions, and patterns
projectMapId, projectMapNodeIdeq, neq, in, nin, defCompositions and patterns

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

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 typeOperators
Text, single selectmatch, starts, eq, neq, in, nin, def
Multi selecteq, neq, in, nin, all, def
Rich textmatch, starts, def
Number, date, date/timeeq, neq, lt, lte, gt, gte, in, nin, def
Booleaneq, neq, def
Reference (entries only), by referenced entry IDeq, neq, in, nin, def
Asset, by asset IDeq, neq, in, nin, def
Link, by pathmatch, starts, eq, neq, in, nin, def

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

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 typeSub-propertyOperators
Reference.name, .slugmatch, starts, eq, neq, in, nin, def
Reference.type, .uiStatuseq, neq, in, nin, def
Asset.url, .title, .descriptionmatch, starts, eq, neq, in, nin, def
Asset.mediaTypeeq, neq, in, nin, def
Link.type, .projectMapNodeIdeq, neq, in, nin, def
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.

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

PropertyType
fields.title, fields.description, fields.url, fields.mediaTypeText
fields.size (bytes), fields.width, fields.height (pixels)Number

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. Search tolerates small typos. The tail of very long text values isn't guaranteed to be searchable.

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.

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.

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.

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 of each item for the requested locale. editions: 'all' returns every edition as its own result.

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'], })
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' }, }, })
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.

  • 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. Combining them with deleted: 'only' or deleted: 'include' returns HTTP 400.