AIVAX

Advanced Filters

An advanced filter, also called a document filter, restricts a RAG search to the documents that match a condition, such as a tag, a metadata value, or a date range. Only documents that pass the filter are ranked by semantic similarity, so results never include documents outside the filter. For a task-oriented walkthrough, see How to filter RAG results by metadata, tags and date.

Filters are evaluated before the search terms are embedded. When no document in the requested collections matches the filter, the request returns an empty result without generating embeddings or charging for the search.

TEXT
tags has "finance"
metadata.department = "finance" and createdAt >= now-30d
(tags has "finance" or tags has "legal") and not tags has "draft"

Anatomy of a Filter #

A filter is one or more conditions joined by and, or, and not. Every condition has three parts:

TEXT
metadata.pages   >   10
└── field ──┘   └op┘ └value┘
  • Field — what to look at: name, content, tags, createdAt, updatedAt, or metadata.<key>. See Fields.
  • Operator — how to compare: =, >, contains, in, has, exists, and others. See Operators.
  • Value — a literal to compare against: a quoted string, a number, true, false, null, a date, or a list in parentheses. See Values.

The value must always be a literal. Functions, arithmetic, type conversions, and comparisons between two fields are not supported. Keywords, operators, and field names are case-insensitive: AND, And, and and are equivalent.

Fields #

FieldTypeSource
nametextThe document name (docid in JSONL imports).
contenttextThe indexed document text.
tagslist of textThe document tags (__tags).
createdAtdate and timeWhen the document was created.
updatedAtdate and timeWhen the document was last updated.
metadata.<key>JSON valueA value inside the document metadata (__meta).

See Documents for how these fields are set.

Operators #

Each operator works only with specific fields and value types. Any other combination, such as tags = "x" or name > "a", is rejected.

Equality #

OperatorMeaningFieldsExample
=Equalsname, content, createdAt, updatedAt, metadata.<key>name = "refund-policy"
!=Not equals; exactly not field = valueSame as =metadata.lang != "en"

For metadata.<key>, the value may be text, a number, true, false, or null. Text comparison ignores letter case and accents; see Strings.

Ordering #

OperatorMeaningFieldsExample
> >= < <=Greater or less thancreatedAt, updatedAt, numeric metadata.<key>metadata.pages > 10

Ordering works on dates for createdAt and updatedAt, and on numbers only for metadata. Dates or text stored in metadata cannot be ordered; see Metadata.

Text #

OperatorMeaningFieldsExample
containsIncludes the text; at least 3 charactersname, content, text metadata.<key>content contains "late fee"
startswithBegins with the textSamename startswith "contract-"
endswithEnds with the textSamename endswith ".pdf"

These operators match literally, without wildcards: % and _ match only themselves. They do not split words or match synonyms. Use the search terms for meaning and the filter for exact constraints.

Lists #

OperatorMeaningFieldsExample
inEquals any value in the listname, content, tags, metadata.<key>metadata.region in ("latam", "emea")
hasThe list contains the valuetags, array metadata.<key>tags has "finance"

field in (a, b, c) is equivalent to field = a or field = b or field = c. For tags, in matches documents that have at least one of the listed tags. has is the only equality-style operator for tags; tags = "x" is rejected.

Existence #

OperatorMeaningFieldsExample
existsThe metadata key is present, even when its value is nullmetadata.<key>metadata.reviewer exists

exists takes no value. To require a non-null value, combine it with !=: metadata.reviewer exists and metadata.reviewer != null.

Values #

Strings #

Strings use double or single quotes. Inside a string, escape the same quote with a backslash: "say \"hi\"", 'it\'s'. Supported escapes are \", \', \\, \/, \n, \r, \t, and \uXXXX.

Text comparisons ignore letter case and accents: name = "relatorio" matches a document named Relatório. = and in also ignore trailing spaces: "report " matches "report".

Numbers #

Numbers use a dot as the decimal separator and may use an exponent: 10, -2.5, 1e3. Numbers are never quoted; "100" is a string.

Booleans and null #

true, false, and null are literals, written without quotes. They are valid only for metadata.<key>.

Dates #

createdAt and updatedAt accept absolute dates and relative times.

Absolute dates use ISO 8601 inside quotes:

TEXT
createdAt >= "2026-09-01"
updatedAt < "2026-09-01T18:30"
createdAt >= "2026-09-01T00:00:00-03:00"
createdAt >= "2026-09-01T03:00:00Z"
  • A date without a time means midnight.
  • A value without Z or an offset is interpreted in the AIVAX service time zone, America/Sao_Paulo (UTC−03:00). Add Z or an offset when you need an exact instant.
  • Other formats, such as 15/06/2025, are rejected.

Relative times use now, optionally followed by + or - and an amount with a unit, without quotes:

UnitMeaning
mminutes
hhours
ddays
wweeks
mocalendar months
ycalendar years
TEXT
createdAt >= now-7d
updatedAt >= now-12h and updatedAt < now

now is valid only in date conditions.

Lists #

A list is one or more values separated by commas inside parentheses: ("finance", "legal"), (2026, "2026"). Lists are used with in.

Combining Conditions #

Join conditions with and, or, and not:

TEXT
not tags has "draft"
tags has "finance" and createdAt >= now-30d
(tags has "finance" or tags has "legal") and updatedAt >= "2026-01-01"

not binds tighter than and, and and binds tighter than or. So a or b and c means a or (b and c). Use parentheses to group explicitly.

Metadata #

Use a dot to read nested metadata. Keys that are not simple identifiers go in quotes:

TEXT
metadata.author.name = "Ana"
metadata."file-path" startswith "/contracts/2026/"
metadata."a.b" = 1

The last example reads one key named a.b, not a nested path. Array indexes are not supported; use has to check whether an array contains a value.

Types are never converted. The literal type selects which stored values can match:

LiteralMatches stored values of type
textJSON string
numberJSON number
true / falseJSON boolean
nullJSON null

So metadata.year = 2026 does not match {"year": "2026"}, and metadata.public = true does not match {"public": "true"}. If your data mixes types, list both: metadata.year in (2026, "2026").

Ordering operators work only on numbers in metadata. Dates stored in metadata cannot be compared as dates; use createdAt and updatedAt, or store a sortable number such as a Unix timestamp or 20260915.

A missing key never matches a positive condition, so metadata.lang != "en" also matches documents without lang. To exclude them, add metadata.lang exists.

Store metadata with consistent types per key, and prefer keys made of ASCII letters, digits, -, and _.

Examples #

GoalFilter
Documents with a tagtags has "finance"
Any of several tagstags in ("finance", "legal")
Exclude draftsnot tags has "draft"
A specific documentname = "refund-policy"
Documents from one familyname startswith "manual-v2-"
Content mentioning a termcontent contains "late fee"
Created in the last 30 dayscreatedAt >= now-30d
Updated in September 2026updatedAt >= "2026-09-01" and updatedAt < "2026-10-01"
One metadata valuemetadata.department = "finance"
Several metadata valuesmetadata.author.name in ("Ana", "Bruno")
Numeric rangemetadata.pages > 10 and metadata.pages <= 200
Boolean flagmetadata.public = true
Metadata array containsmetadata.languages has "pt-BR"
Key present and not nullmetadata.reviewer exists and metadata.reviewer != null
Key absentnot metadata.archived exists
Combined(tags has "finance" or metadata.department = "finance") and createdAt >= now-1mo

Common Mistakes #

Instead ofWrite
name == "x"name = "x"
lower(name) = "x"name = "x" (already case-insensitive)
tags = "x"tags has "x"
metadata.price > "100"metadata.price > 100, with the price stored as a number
createdAt >= "15/06/2025"createdAt >= "2025-06-15"
metadata.date >= "2025-06-15"createdAt >= "2025-06-15", or a numeric metadata value
content contains "ai"A term with at least 3 characters
"filters": [ ... ]"filter": [ ... ]

Where Filters Are Supported #

Send the filter in the filter field of these endpoints:

The field accepts a string or an array of strings. Array items are combined with and:

JSON
{
  "term": "How do I request a refund?",
  "collections": [ "<collection-id>" ],
  "filter": [
    "tags has \"billing\"",
    "metadata.region = \"latam\""
  ]
}

A missing or null field means no filter. The field name is filter; other names, such as filters, are ignored and the search runs without a filter.

Models can also send a filter string in the optional filter argument of these tools:

The memory_search tool also accepts a filter string, but requires exactly one of query or filter, not both. Its filter-only mode returns up to 10 matching memories for the current user, newest first, without query embeddings.

Automatic gateway RAG, which searches before the model call, does not apply filters. An invalid filter in a tool call is returned to the model as a tool error with the same message as the API.

Limits #

These limits apply to every filter, including filters used by memory search and the Collections MCP.

LimitValue
Filter length2,048 characters per string
Conditions32 per string
Nesting of parentheses and not8 levels
Values in one in list100
Length of a text value or metadata key256 characters
Keys in a metadata path8
Minimum contains length3 characters
Execution time10 seconds

Conditions on content, endswith, tags, and metadata examine every document in the requested collections, so they take longer in large collections. If a filter exceeds the time limit, the request fails and asks for more selective conditions. Prefer conditions on name (=, in, startswith), split very large corpora into smaller collections, and reserve content contains for collections where it stays fast.

Errors #

An invalid filter returns 400 Bad Request with a message that names the problem and the character position where it was found:

JSON
{
  "error": "Invalid filter: Unknown field 'author'. Expected name, content, tags, createdAt, updatedAt or metadata.<key>. (at 0)"
}

For an array, the message includes the index of the invalid item, such as Invalid filter at index 1: .... A filter that is not a string or an array of strings is also rejected.

Type to search the documentation.