Skip to main content

Filter Registration API

The Filter Registration endpoints allow you to define how user context (access rules, ownership scope, and session filters) maps to metadata filters on each nexset. Once registered, the Agentic RAG endpoint automatically resolves these schemas at query time, converting the caller's user_context into per-nexset access control and pre-retrieval filters.

Base path: /v2/nexsets/{nexset_id}/filters

Authentication

All endpoints require an Authorization header. See the GenAI RAG API overview for full details.

Access is role-gated against the target nexset via the Nexla Admin API:

  • Read endpoints (GET) require at least collaborator role on the nexset
  • Write endpoints (POST, PATCH, DELETE, refresh) require at least operator role on the nexset

Concepts

Filter Types

Each filter entry belongs to one of three layers, which determines how the value is sourced from user_context at query time:

TypeSource at Query TimeApplied AsDescription
access_rulesuser_context.access_rulesACL filterPolicy-level gates (e.g., "can this user access confidential docs?")
access_scopeuser_context.access_scopeACL filterData ownership scope (e.g., "only docs from this tenant"). Values use IN semantics
filtersuser_context.filtersPre-retrieval filterPage or session context (e.g., "only docs from this project")
Key Principle

Filters can never expand access beyond what access_rules and access_scope permit. If a key appears in both access_scope and filters, Nexla applies the intersection — filters only narrow, never broaden.

Filter Operators

OperatorValue TypeDescription
EQsingle valueEquals
NEQsingle valueNot equals
INarrayValue is in the provided list
NOT_INarrayValue is not in the provided list
GTsingle valueGreater than
GTEsingle valueGreater than or equal
LTsingle valueLess than
LTEsingle valueLess than or equal
CONTAINSsingle valueField contains the value (substring match)
NOT_CONTAINSsingle valueField does not contain the value
EXISTS(ignored)Field exists and is not null
NOT_EXISTS(ignored)Field does not exist or is null
BETWEENarray of two values [min, max]Value is within the inclusive range

Filter Registration Entry

Used in the request body for POST /v2/nexsets/{nexset_id}/filters:

FieldTypeRequiredDefaultDescription
keystringYesMetadata field name to filter on. Must match ^[\w\-\.]{1,255}$
typestringYesFilter type: "access_rules", "access_scope", or "filters"
operatorstringNo"EQ"Default comparison operator for this filter
descriptionstring or nullNonullHuman-readable description
nexset_fieldstring or nullNonullBackend field name, if it differs from key. When set, key is used to look up the value in user_context and nexset_field is the actual metadata field or column consulted by the backend
note

nexset_field allows decoupling the user_context key name from the actual backend metadata field. For example, you might register key: "tenant_id" with nexset_field: "org_tenant" so that callers use "tenant_id" in user_context while the backend filters on the "org_tenant" column.

Filter Entry Object

All endpoints that return filter data use this object shape:

FieldTypeDescription
idintegerUnique identifier for this filter entry
nexset_idstringThe nexset this filter belongs to
keystringThe metadata field name
typestringFilter layer: "access_rules", "access_scope", or "filters"
operatorstringThe comparison operator applied at query time
descriptionstring or nullHuman-readable description
nexset_fieldstring or nullBackend field override, if any
created_atstringISO-8601 timestamp of creation
updated_atstringISO-8601 timestamp of last update

Endpoints

Register Filter Schema

POST /v2/nexsets/{nexset_id}/filters

Register or replace the full filter schema for a nexset. This replaces all existing filters for the nexset.

Path Parameters

ParameterTypeDescription
nexset_idstringThe nexset identifier. Must match ^[\w\-\.]{1,255}$

Request Body

FieldTypeRequiredDescription
filtersarray of FilterRegistrationEntryYesThe filter entries to register

Response

Status: 200 OK

{
"nexset_id": "10000",
"filters": [
{
"id": 1,
"nexset_id": "10000",
"key": "tenant_id",
"type": "access_scope",
"operator": "IN",
"description": "Restrict results to the user's tenant",
"nexset_field": null,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
},
{
"id": 2,
"nexset_id": "10000",
"key": "classification",
"type": "access_rules",
"operator": "EQ",
"description": "Document classification level",
"nexset_field": null,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-15T10:30:00Z"
}
]
}

Get Filter Schema

GET /v2/nexsets/{nexset_id}/filters

Retrieve the current filter schema for a nexset.

Path Parameters

ParameterTypeDescription
nexset_idstringThe nexset identifier. Must match ^[\w\-\.]{1,255}$

Response

Status: 200 OK

Returns the same envelope as the register endpoint. The filters array is empty when no schema has been registered for the nexset.


Update a Filter Key

PATCH /v2/nexsets/{nexset_id}/filters/{key}?type={type}

Update a single filter key. The type query parameter identifies which filter entry to update when the same key exists under multiple types.

Path Parameters

ParameterTypeDescription
nexset_idstringThe nexset identifier. Must match ^[\w\-\.]{1,255}$
keystringThe filter key name. Must match ^[\w\-\.]{1,255}$

Query Parameters

ParameterTypeRequiredDescription
typestringYesThe current filter type of the entry to update: "access_rules", "access_scope", or "filters"

Request Body

All fields are optional. Include only the fields you want to change. At least one must be present.

FieldTypeRequiredDescription
typestringNoMove this filter to a different type
operatorstringNoUpdate the comparison operator
descriptionstringNoUpdate the description
nexset_fieldstringNoUpdate the backend field override

Response

Status: 200 OK

Returns the updated Filter Entry Object.

{
"id": 1,
"nexset_id": "10000",
"key": "tenant_id",
"type": "access_rules",
"operator": "EQ",
"description": "Updated description",
"nexset_field": null,
"created_at": "2025-01-15T10:30:00Z",
"updated_at": "2025-01-16T14:00:00Z"
}

Delete a Filter Key

DELETE /v2/nexsets/{nexset_id}/filters/{key}?type={type}

Remove a single filter key from a nexset.

Path Parameters

ParameterTypeDescription
nexset_idstringThe nexset identifier. Must match ^[\w\-\.]{1,255}$
keystringThe filter key name. Must match ^[\w\-\.]{1,255}$

Query Parameters

ParameterTypeRequiredDescription
typestringYesThe filter type to delete: "access_rules", "access_scope", or "filters"

Response

Status: 204 No Content

No response body.


Refresh Filter Cache

POST /v2/nexsets/{nexset_id}/filters/refresh

Invalidates the Redis-backed filter schema cache for the nexset. The next V2 query that needs this nexset's registered filter keys reloads them from Supabase and writes the refreshed schema back to cache.

Path Parameters

ParameterTypeDescription
nexset_idstringThe nexset identifier. Must match ^[\w\-\.]{1,255}$

Response

Status: 200 OK

{
"status": "ok",
"nexset_id": "10000"
}

Error Reference

All error responses use the standard JSON format:

{
"detail": "Error message describing the issue"
}
StatusConditionRetryable
400Invalid nexset_id or key format; PATCH body contains no updatable fieldsNo
401Missing or invalid Authorization headerNo
403Caller lacks the required role on the nexset (read: collaborator; write: operator)No
404Nexset not found, or filter {key, type} pair not found (PATCH/DELETE)No
409PATCH tries to move an entry to a type where the same key already existsNo
422Missing or invalid ?type= query parameter on PATCH/DELETENo
500Internal server error during registration/update/lookupMaybe
502Upstream Admin API error while resolving role for the nexsetYes
503Filter registration backend (Supabase) is not configured on this deploymentNo

Cache Behavior

Nexla caches filter schema per nexset to avoid a database read on every query. The cache is managed as follows:

  • POST /v2/nexsets/{nexset_id}/filters — replaces schema and invalidates cache automatically
  • PATCH /v2/nexsets/{nexset_id}/filters/{key}?type={type} — updates key and invalidates cache automatically
  • DELETE /v2/nexsets/{nexset_id}/filters/{key}?type={type} — removes key and invalidates cache automatically
  • POST /v2/nexsets/{nexset_id}/filters/refresh — explicit cache invalidation, for operational use or after out-of-band changes
Unregistered Keys

If a filter key passed at query time is not registered for a given nexset, Nexla silently skips it for that nexset. In debug mode, unregistered keys are surfaced in intermediate_responses.skipped_filter_keys so the caller can identify mismatches during development.

Examples

Register a Filter Schema

curl -X POST https://api-genai.nexla.io/v2/nexsets/10000/filters \
-H "Content-Type: application/json" \
-H "Authorization: Basic YOUR_API_KEY" \
-d '{
"filters": [
{
"key": "tenant_id",
"type": "access_scope",
"operator": "IN",
"description": "Restrict results to the user tenant"
},
{
"key": "classification",
"type": "access_rules",
"operator": "EQ",
"description": "Document classification level"
},
{
"key": "project_id",
"type": "filters",
"operator": "EQ",
"description": "Page-level project filter"
}
]
}'

Retrieve the Filter Schema

curl https://api-genai.nexla.io/v2/nexsets/10000/filters \
-H "Authorization: Basic YOUR_API_KEY"

Update a Single Filter Key

Change the operator for the tenant_id filter from IN to EQ:

curl -X PATCH "https://api-genai.nexla.io/v2/nexsets/10000/filters/tenant_id?type=access_scope" \
-H "Content-Type: application/json" \
-H "Authorization: Basic YOUR_API_KEY" \
-d '{
"operator": "EQ"
}'

Move a filter key to a different type:

curl -X PATCH "https://api-genai.nexla.io/v2/nexsets/10000/filters/project_id?type=filters" \
-H "Content-Type: application/json" \
-H "Authorization: Basic YOUR_API_KEY" \
-d '{
"type": "access_scope"
}'

Delete a Filter Key

curl -X DELETE "https://api-genai.nexla.io/v2/nexsets/10000/filters/classification?type=access_rules" \
-H "Authorization: Basic YOUR_API_KEY"

Refresh the Filter Cache

curl -X POST https://api-genai.nexla.io/v2/nexsets/10000/filters/refresh \
-H "Authorization: Basic YOUR_API_KEY"

End-to-End: Register Filters Then Query

  1. Register a filter schema that enforces tenant isolation:
curl -X POST https://api-genai.nexla.io/v2/nexsets/10000/filters \
-H "Content-Type: application/json" \
-H "Authorization: Basic YOUR_API_KEY" \
-d '{
"filters": [
{
"key": "tenant_id",
"type": "access_scope",
"operator": "IN",
"description": "Tenant isolation"
}
]
}'
  1. Query the Agentic RAG endpoint. The server automatically resolves user_context.access_scope.tenant_id into an ACL filter:
curl -X POST https://api-genai.nexla.io/v2/agentic-rag \
-H "Content-Type: application/json" \
-H "Authorization: Basic YOUR_API_KEY" \
-d '{
"user_prompt": "What are the Q2 sales figures?",
"nexsets": ["10000"],
"user_context": {
"user_id": "user-123",
"access_scope": { "tenant_id": ["tenant-1"] }
},
"llm_config": { "credential_id": "cred-456" }
}'

The search results will only include records where tenant_id matches "tenant-1".