Skip to main content

Search Filters

POST /search returns the Evidence Result contract. Each row represents one Document Version with canonical metadata, lane-local retrieval contributions, and bounded Content and Metadata Evidence Sets. Pagination and meta.total count Document Versions, not chunks or Metadata Leaves.

For ordinary text retrieval, send explicit "scope": "content". scope is case-insensitive; the canonical values used in requests and downstream processing are lowercase: content, metadata, and both.

Exact filters are not ranked Metadata search. The filters object only narrows the candidate set and never changes retrieval rank. Ranked Metadata search uses "scope": "metadata" or "scope": "both" and is documented in Searching Metadata. This guide documents exact filter constraints only.

Filters narrow the candidate set by document metadata, classifier categories, custom fields uploaded with a document, and entities extracted during processing. They are exact constraints: they do not affect result rank.

Search filters (POST /search)​

Scalar values match exactly. A list of strings or integers uses OR logic within that key. Keys are combined with AND logic:

{
"query": "capital city",
"scope": "content",
"filters": {
"document_id": "malaysia-wiki-001",
"classification.categories": ["sustainability", "other"]
}
}

This requires the document_id constraint and either listed classifier category. Filters do not change the rank or retrieval contributions of a returned Evidence Result.

Including soft-deleted evidence​

Soft-deleted Document Versions and their evidence are hidden by default. Set include_deleted to true only for an intentional audit or restore workflow:

curl -X POST http://localhost:8000/search \
-H "X-API-Key: super-secret-key" \
-H "Content-Type: application/json" \
-d '{
"query": "capital city",
"scope": "content",
"include_deleted": true
}'

include_deleted changes lifecycle visibility only. The request remains scoped to the Client resolved from X-API-Key, the active generation, and publication_eligible versions. It never bypasses Client isolation or publication authority checks.

Custom metadata filters​

Any custom metadata uploaded through /embed or /update can be used as an exact filter. Custom metadata keys must use the explicit metadata.custom. prefix in filters. Top-level fields, entity keys, and documented system shorthands are the only keys accepted bare:

Request keyResolved payload key
metadata.custom.departmentmetadata.custom.department
source.filenamemetadata.source.filename
metadata.source.filenamemetadata.source.filename
document_iddocument_id
version_idversion_id
created_atcreated_at

An unqualified key that is not a top-level field (document_id, version_id, created_at), entity key (e.g. persons, organizations), or documented system shorthand (e.g. source.filename, classification.status) is rejected with 400. Dotted identifier keys remain nested paths; keys with spaces or other unsupported path characters are quoted as one custom key.

# Upload with custom metadata
curl -X POST http://localhost:8000/embed \
-H "X-API-Key: super-secret-key" \
-F "file=@resume.pdf" \
-F "document_id=candidate-001" \
-F 'metadata={"department":"Engineering","team":"Backend","author":["wanjia","adlin"]}'

# Filter by custom metadata
curl -X POST http://localhost:8000/search \
-H "X-API-Key: super-secret-key" \
-H "Content-Type: application/json" \
-d '{
"query": "python developer",
"scope": "content",
"filters": {
"metadata.custom.department": "Engineering",
"metadata.custom.team": "Backend"
}
}'

Custom metadata filter keys use the explicit metadata.custom. prefix. Lists match any value within that key while other keys remain AND constrained:

curl -X POST http://localhost:8000/search \
-H "X-API-Key: super-secret-key" \
-H "Content-Type: application/json" \
-d '{
"query": "budget report",
"scope": "content",
"filters": {
"metadata.custom.tenant_id": "tenant-a",
"metadata.custom.department": ["Finance", "Operations"]
}
}'

This searches within tenant-a across both Finance and Operations without changing Evidence Result rank.

Keys with spaces (or other special characters)​

Custom metadata keys with spaces must use the explicit metadata.custom. prefix. Quote the key in the JSON filter. For a body-based POST /search filter, the JSON key is used directly. For GET /documents, URL-encode the entire JSON value in metadata_filter:

curl -sS --get "http://localhost:8000/documents" \
-H "X-API-Key: super-secret-key" \
--data-urlencode 'metadata_filter={"metadata.custom.Field A":"Acme"}' \
| jq '{documents: [.documents[] | {document_id, metadata: {custom: .metadata.custom}}], total, has_more}'

The trimmed response contains only the document whose exact Field A value is Acme:

{
"documents": [
{
"document_id": "spaced-key-demo.txt",
"metadata": {"custom": {"Field A": "Acme"}}
}
],
"total": 1,
"has_more": false
}

Client isolation and reserved filter keys​

Results are automatically scoped to the Client that owns the API key. Callers never provide client_id and cannot filter by it. The client_id key is reserved top-level system state, as are the Soft Delete markers deleted, deleted_at, and deleted_by. Attempting to use a reserved key returns 400:

{"detail":"Reserved filter keys are not allowed: client_id"}
{"detail":"Reserved filter keys are not allowed: deleted"}

This also applies to metadata.custom.* aliases. Both metadata.custom.client_id and metadata.custom.deleted are rejected rather than treated as user metadata. Use include_deleted=true for read visibility and POST /document/{document_id}/restore to clear deletion markers.

Unsupported metadata.* paths, legacy metadata.parsing.*, metadata.processing.*, and metadata.ocr.* paths, and unsupported entities.* paths are rejected with 400; they do not fall back to custom metadata. A bare key that is not a top-level field, entity key, or documented system shorthand is also rejected with 400; custom metadata requires the explicit metadata.custom. prefix. This fail-closed behavior prevents a misspelled or bare custom key from silently matching nothing or the wrong field.

System metadata filters​

Filter system-generated metadata with the documented dotted paths. The full metadata.* path also works:

curl -X POST http://localhost:8000/search \
-H "X-API-Key: super-secret-key" \
-H "Content-Type: application/json" \
-d '{
"query": "quarterly report",
"scope": "content",
"filters": {
"source.filename": "report.pdf",
"location.page_number": 1
}
}'

Available system metadata paths:

PathFull pathTypeExampleDescription
source.filenamemetadata.source.filenamestring"report.pdf"Source filename. Set from the upload name at embed time; rename later with PATCH /update filename.
source.mime_typemetadata.source.mime_typestring"application/pdf"Original MIME type
source.extensionmetadata.source.extensionstring"pdf"Original extension
location.page_numbermetadata.location.page_numberinteger1Page number
location.page_labelmetadata.location.page_labelstring"1"Page label
location.chunk_indexmetadata.location.chunk_indexinteger0Chunk index within the version
document.page_countmetadata.document.page_countinteger10Total page count
classification.categoriesmetadata.classification.categoriesstring or list"risk management"Assigned categories
classification.statusmetadata.classification.statusstring"completed"Classification state
quality.text_extractionmetadata.quality.text_extractionstring"native" or "ocr"Extraction method
quality.ocr_usedmetadata.quality.ocr_usedbooleantrue or falseWhether OCR was used
extracted.titlemetadata.extracted.titlestring"Annual Report"Extracted title
extracted.authormetadata.extracted.authorstring"Jane Doe"Extracted author
extracted.created_atmetadata.extracted.created_atstring"2026-04-09"Extracted creation date
metadata.custom.*metadata.custom.*anyuser-definedCustom uploaded metadata

Entity filters​

Entity filters target values extracted during document processing. Use one string or a list of strings. A list uses OR semantics within that key; different keys use AND semantics.

Single string value​

curl -X POST http://localhost:8000/search \
-H "X-API-Key: super-secret-key" \
-H "Content-Type: application/json" \
-d '{
"query": "quarterly earnings",
"scope": "content",
"filters": {
"persons": "John Doe"
}
}'

List value (OR semantics)​

curl -X POST http://localhost:8000/search \
-H "X-API-Key: super-secret-key" \
-H "Content-Type: application/json" \
-d '{
"query": "loan application",
"scope": "content",
"filters": {
"organizations": ["Bank A", "Bank B"]
}
}'

This returns Evidence Results whose Content evidence contains either Bank A or Bank B.

AND across filter keys​

curl -X POST http://localhost:8000/search \
-H "X-API-Key: super-secret-key" \
-H "Content-Type: application/json" \
-d '{
"query": "quarterly earnings",
"scope": "content",
"filters": {
"persons": "John Doe",
"organizations": ["Bank A", "Bank B"]
}
}'

This returns Document Versions whose Content evidence satisfies both entity constraints.

Filter keyExampleDescription
persons"John Doe"People mentioned in the document
organizations"Bank of America"Companies, banks, and institutions
dates"2024-01-15"Dates and time expressions
locations"New York"Geographic locations
monetary_amounts"$1,000,000"Currency and monetary values
account_numbers"1234567890"Account numbers
transaction_refs"TXN-12345"Transaction references
account_types"savings"Account types

Entity filters can be combined with custom metadata and system metadata filters in the same request:

curl -X POST http://localhost:8000/search \
-H "X-API-Key: super-secret-key" \
-H "Content-Type: application/json" \
-d '{
"query": "quarterly earnings",
"scope": "content",
"filters": {
"metadata.custom.department": "Engineering",
"metadata.custom.project": "alpha",
"persons": "John Doe",
"organizations": ["Acme Corp", "Globex"]
}
}'

Document listing filters (GET /documents)​

Document listing filters are separate from /search filters. GET /documents supports scalar metadata equality filters; use POST /search for list values. Document listings hide soft-deleted versions by default; add include_deleted=true to include lifecycle markers:

curl "http://localhost:8000/documents?include_deleted=true" \
-H "X-API-Key: super-secret-key"

Do not filter directly on deleted, deleted_at, or deleted_by; those markers are reserved system state, not user metadata.