Filter Operators
Filter operators let you narrow bucket search results by metadata predicates. In the v2 bucket search request body, pass them inside the filter object. Plain scalar values are exact-match shortcuts; wrap a value in an operator object to express richer predicates.
Note: Metadata values are stored and compared as strings. Booleans become
"true"/"false"and numbers are coerced to strings before matching.
API Versions
Section titled “API Versions”| Version | Status | Notes |
|---|---|---|
v2 | Current | POST /v2/buckets/\{bucket_id\}/search. Use for all new integrations. |
v1 | Deprecated | POST /v1/buckets/\{bucket_id\}/search is kept for existing clients and returns Deprecation, Warning, and Link headers pointing to the v2 successor. |
Legacy v1 endpoint
Section titled “Legacy v1 endpoint”POST /v1/buckets/\{bucket_id\}/search is deprecated and accepts the same filter operators documented on this page. New integrations should use POST /v2/buckets/\{bucket_id\}/search instead.
Operators
Section titled “Operators”| Operator | Type | Example | Notes |
|---|---|---|---|
eq | any | {"eq": "urgent"} | Exact match. Top-level eq is lowered to the engine fast path. |
ne | any | {"ne": "draft"} | Not-equal. Applied as a post-filter. |
like | string | {"like": "%legal%"} | SQL LIKE: % matches any sequence, _ matches one char, \% / \_ are literals. Case-insensitive. |
prefix | string | {"prefix": "2024-"} | Starts-with. Case-insensitive. |
in | array | {"in": ["a", "b"]} | Membership test. Maximum 100 entries. |
gt / gte | number / ISO date | {"gte": 0.8} | Greater-than (or equal). |
lt / lte | number / ISO date | {"lt": 100} | Less-than (or equal). |
exists | boolean | {"exists": true} | Field presence: true means present and non-empty; false means missing or empty. |
Each operator object must contain exactly one key. A single filter key can use only one operator at a time.
Cross-key OR ($or)
Section titled “Cross-key OR ($or)”Use $or to express disjunctions across different metadata keys. $or accepts a list of sub-filter dictionaries and can be nested up to 3 levels.
{ "filter": { "doc_type": "policy", "$or": [ {"severity": "high"}, {"priority": {"in": ["P0", "P1"]}} ] }}Top-level keys are still AND. The example matches documents where doc_type = "policy" AND (severity = "high" OR priority ∈ {"P0", "P1"}). Each arm is a full sub-filter and can use any operator. A single $or list supports up to 16 arms.
Semantics
Section titled “Semantics”- Top-level keys in
filterare conjunctive (AND). - Same-key OR uses the
inoperator; cross-key OR uses$or. - Exact-match keys are pushed to the vector engine for pruning. Operator keys are evaluated server-side on returned candidates, so the engine fast path stays untouched.
Safety limits
Section titled “Safety limits”| Limit | Value |
|---|---|
Max filter JSON size (internal filter query param) | 8 KB |
| Max filter nesting depth | 16 |
like / prefix pattern length | 256 characters |
like wildcard count (% + _) | 16 |
in list length | 100 entries |
$or nesting depth | 3 levels |
$or arms per list | 16 |
Patterns are translated to anchored case-insensitive regex with all regex metacharacters escaped, so there is no SQL injection surface.
POST /v2/buckets/{bucket_id}/search
Section titled “POST /v2/buckets/{bucket_id}/search”Search a bucket with a text query and metadata filters.
Path parameters
Section titled “Path parameters”| Name | Type | Description |
|---|---|---|
bucket_id | string | UUID or slug of the bucket to search. |
Request body
Section titled “Request body”| Field | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | Yes | — | Natural-language query. Maximum 8,192 characters. |
top_k | integer | No | 10 | Maximum number of results to return. |
filter | object | No | null | Metadata predicates. Plain values are exact match; operator objects use the operators above. |
mode | string | No | "hybrid" | "vector" or "hybrid". |
rerank | boolean | No | false | Whether to rerank candidates. |
min_score | number | No | null | Minimum score threshold (0.0–1.0). |
Example request
Section titled “Example request”curl -X POST ${API_BASE_URL:-https://api.schift.io}/v2/buckets/product-docs/search \ -H "Authorization: Bearer $SCHIFT_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "query": "fire safety inspection cycle", "top_k": 10, "filter": { "tag": "urgent", "source_url": {"like": "%fire-safety%"}, "filename": {"prefix": "2024-"}, "doc_type": {"in": ["policy", "spec"]}, "score": {"gte": 0.8}, "stage": {"ne": "draft"}, "author": {"exists": true}, "$or": [ {"severity": "high"}, {"priority": {"in": ["P0", "P1"]}} ] } }'Response
Section titled “Response”| Field | Type | Description |
|---|---|---|
bucket_id | string | Bucket that was searched. |
query | string | Query that was executed. |
search_id | string | null | Server-generated search identifier. |
results | array | Matching chunks, ordered by relevance. |
results[].id | string | Chunk identifier. |
results[].score | number | Final relevance score. |
results[].text | string | Chunk text. |
results[].metadata | object | Chunk metadata. |
results[].citation | string | null | Formatted citation, if requested. |
degraded | boolean | Whether the response was produced in a degraded mode. |
warnings | array | Search warnings, if any. |
Example response
Section titled “Example response”{ "bucket_id": "product-docs", "query": "fire safety inspection cycle", "search_id": "srch_01j8x9q2mvk8r", "results": [ { "id": "chunk_01j8x9q2mvn9q", "score": 0.91, "text": "Annual fire safety inspections must follow the 2024 inspection cycle.", "metadata": { "doc_type": "policy", "filename": "2024-fire-safety.pdf", "tag": "urgent", "author": "safety-team" }, "citation": "[1] 2024-fire-safety.pdf, p. 4" } ], "degraded": false, "warnings": []}Error examples
Section titled “Error examples”// 400 Bad Request — invalid operator combination{ "detail": "FilterOperator must have exactly one of eq/ne/like/prefix/in/gt/gte/lt/lte/exists"}// 400 Bad Request — unsupported filter key{ "detail": "Invalid filter: unsupported metadata key 'internal_tag'"}// 413 Payload Too Large — filter exceeds size limit{ "detail": "filter parameter exceeds 8KB"}// 413 Payload Too Large — filter too deeply nested{ "detail": "filter JSON exceeds nesting depth"}// 402 Payment Required — search quota exhausted{ "allowed": false, "reason": "quota_exceeded"}// 403 Forbidden — search quota unavailable{ "detail": "Search quota unavailable. Upgrade your plan."}// 404 Not Found{ "detail": "Bucket 'product-docs' not found"}