Search Filters
The Search Publications endpoint accepts a ?filters query parameter with a JSON-encoded query DSL for filtering documents by metadata and system fields.
Filter Fields
System fields
These fields come from the document's systemdata and are available for all documents.
| Property | Type |
|---|---|
| documentId | long |
| contentType | keyword |
| firstPublicationDate | date |
| lastPublicationDate | date |
| significantPublicationDate | date |
| visiblePublicationDate | date |
Publish control
Embargo fields exposed from internal editorial workflows. Only present on documents that use the embargo feature.
| Property | Type |
|---|---|
| publishControl.embargo.enforced | boolean |
| publishControl.embargo.until | date |
Statistics
Internally measured document statistics.
| Property | Type |
|---|---|
| statistics.characterCount | integer |
| statistics.componentCount.* | integer |
Metadata fields
metadata.* covers all user-configured metadata properties. These are the fields you define in your project configuration. Metadata fields are the most common filter target for customer-specific use cases — filtering articles by topic, language, content classification, or any other custom property.
To be filterable, a metadata field needs two things:
- The plugin must support indexing (most do — see the table below)
- The field must have
index: trueset in the content type's metadata configuration
The filter key is metadata.<handle> for simple-value plugins, or metadata.<handle>.<key> for plugins that store objects with nested indexed properties.
Common plugins and their index types
| Plugin | Stores | Index type | Filter key example |
|---|---|---|---|
li-text | string | keyword, text | metadata.title |
li-boolean | boolean | boolean | metadata.news |
li-enum | string | keyword, text | metadata.status |
li-integer | number | integer | metadata.priority |
li-datetime | ISO date string | date | metadata.deadline |
li-date | ISO date string | date | metadata.publishDate |
li-language | {locale, ...} | keyword | metadata.language.locale |
li-category | {id, path} | keyword | metadata.category.id |
li-document-reference | {reference: {id}} | keyword | metadata.author.reference.id |
li-document-references | {references: [{id}]} | keyword | metadata.related.references.id |
li-string-list | string array | keyword, text | metadata.tags |
Some plugins index the same value as both keyword (for exact match filtering) and text (for full-text search). The keyword type is used when filtering, while text is used when a ?search term matches against indexed metadata.
For the full list of plugin capabilities, consult your project configuration reference.
When querying a metadata property that stores an object, always use the key of a leaf node (e.g. metadata.teaserImage.mediaId), because only the indexed sub-properties are filterable, not the parent object itself.
Supported query capabilities by type
The index type of each field determines which query capabilities are supported:
| Type | Term | Range | Exists | Sort |
|---|---|---|---|---|
| keyword | yes | yes | yes | yes |
| integer | yes | yes | yes | yes |
| float | yes | yes | yes | yes |
| double | yes | yes | yes | yes |
| long | yes | yes | yes | yes |
| date | yes | yes | yes | yes |
| boolean | yes | — | yes | — |
Query Expressions
Term
Exact match comparison. Some type coercion may be applied.
{
key: 'metadata.title',
term: 'My Title'
}
An array can be provided as the term value, which behaves like an OR:
{
key: 'metadata.language.locale',
term: ['de', 'fr']
}
Range
Search within a range. Operators gt, gte, lt, lte can be combined.
{
key: 'metadata.count',
range: {gt: 1, lt: 5}
}
Exists
Check if a property has been set.
{
key: 'metadata.teaserImage.mediaId',
exists: true
}
Logical Operators
Logical operators group queries and override the default AND behaviour of the top-level array. Operator values can be an object or an array containing other operators or query expressions.
AND
All conditions must be met.
{
and: [
{key: 'metadata.news', term: true},
{key: 'metadata.teaserImage.mediaId', exists: false}
]
}
OR
Any condition can be met.
{
or: [
{key: 'metadata.image.mediaId', exists: true},
{key: 'metadata.teaserImage.mediaId', exists: true}
]
}
NOT
Negates the expression. To negate multiple conditions, nest another logical operator within.
{
not: {key: 'metadata.language.locale', term: 'de'}
}
{
not: {
or: [
{key: 'metadata.news', term: false},
{key: 'metadata.language.locale', term: 'fr'}
]
}
}
Full Example
Combining logical operators and query expressions into a more complex query:
const filters = JSON.stringify({
or: [
{
and: [
{key: 'metadata.count', range: {lte: 2}},
{key: 'metadata.bool', exists: true},
{not: {key: 'metadata.title', term: 'My Title'}}
]
},
{key: 'metadata.count', term: 3}
]
})
const response = await fetch(
`https://server.livingdocs.io/api/2026-01/publications/search?filters=${filters}`,
{headers: {Authorization: 'Bearer ey1234'}}
)
const {results} = await response.json()
Sort Fields
The ?sort parameter accepts a comma-separated list of fields. Prefix with - to reverse the order (e.g. -sortDate,documentId).
Valid sort fields:
relevance(only effective with a?searchterm)sortDate(default, descending)documentIdcontentTypefirstPublicationDatelastPublicationDatesignificantPublicationDatevisiblePublicationDatemetadata.*publishControl.embargo.until
Documents without an indexed value for the sort field appear at the end of the results.
Using Filters with curl
filters=$(cat <<'EOF' | jq -c
{
"key": "metadata.language.locale",
"term": "de"
}
EOF
)
curl -s "https://server.livingdocs.io/api/2026-01/publications/search?filters=$filters" \
-H "Authorization: Bearer $ACCESS_TOKEN"