---
title: Filter and paginate results
description: Select data, order Search pages, and use continuation cursors.
doc_version: 0.1.0-preview
last_updated: 2026-09-14
---

# Filter and paginate results

Select the right files, order a page of Search results, and continue through responses with cursors. Filters narrow data; access rules authorize readers.

## Build a filter

Search, Answer, and Research accept a `filter` object. A leaf clause has `field`, `op`, and `value`. Combine clauses with `and`, `or`, or `not`. The filter below selects production incident files. It needs `environment` in the collection’s metadata fields.

**PATCH https://engine.example.com/namespaces/acme/collections/incident-logs/metadata-fields**

```http
PATCH /namespaces/acme/collections/incident-logs/metadata-fields HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
Content-Type: application/json

{
  "fields": {
    "environment": {
      "type": "text"
    }
  }
}
```

A filter can read a metadata key only when the collection lists it, with a type: `text`, `number`, `time`, or `bool`. A new collection lists no key. A change returns `202` with a `reindex_metadata` job. On a collection with files, the index is rebuilt in the background, and the job stays `running` until the rebuild is done. Filters read the old index until the job succeeds. See [Update metadata fields](/engine/reference/update-metadata-fields).

**POST https://engine.example.com/namespaces/acme/collections/incident-logs:search**

```http
POST /namespaces/acme/collections/incident-logs:search HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
Content-Type: application/json

{
  "query": "checkout",
  "mode": "keyword",
  "filter": {
    "and": [
      {
        "field": "path",
        "op": "prefix",
        "value": "/incidents/"
      },
      {
        "field": "metadata.environment",
        "op": "eq",
        "value": "production"
      }
    ]
  },
  "limit": 10
}
```

| Field or operator | Meaning |
| --- | --- |
| Built-in fields | `path`, `content_type`, `bytes`, `created_at`, `updated_at`, and `status`. |
| Metadata fields | Use `metadata.{key}`, such as metadata.environment. The key must be a listed metadata field. Its type sets the operators. `text` takes all of them. `number` takes `eq`, `neq`, `gt`, `gte`, `lt`, `lte`, and `in`. `time` takes `eq`, `neq`, `gt`, `gte`, `lt`, and `lte`. `bool` takes `eq`, `neq`, and `in`. |
| `eq`, `neq` | Equal or unequal to one value. |
| `gt`, `gte`, `lt`, `lte` | Ordered comparisons with a compatible value type. |
| `prefix` | A string begins with the supplied prefix. |
| `in` | The field matches a value in the supplied array. |
| `and`, `or`, `not` | Combine clauses or negate one clause. |

Use values that match the field: numeric byte counts, UTC timestamp strings, and text for paths or media types. A metadata value is read by its field type, so a `number` field takes `10` or `"10"`. Unsupported fields, operators, or value combinations return `400 invalid_filter`. Its details can name the field or operator. For a metadata key that is not listed, `details.reason` is `not_listed`.

## Paginate resource lists

Resource lists use query parameters `limit` and `cursor`. They return `items` and `next_cursor`. The default page size is 50 and the maximum is 100.

**GET https://engine.example.com/namespaces/acme/collections/incident-logs/files?prefix=/incidents/&limit=1**

```http
GET /namespaces/acme/collections/incident-logs/files?prefix=/incidents/&limit=1 HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
```

**200 OK · illustrative continuation token**

```json
{
  "items": [
    {
      "id": "fil_01J8Z3K4N5P6Q7R8S9T0V1W2X3",
      "path": "/incidents/checkout.txt",
      "status": "ready",
      "stage": null,
      "source": {
        "type": "inline",
        "content_type": "text/plain",
        "bytes": 118
      },
      "metadata": {
        "environment": "production",
        "service": "checkout"
      },
      "created_at": "2026-10-06T12:00:00Z",
      "updated_at": "2026-10-06T12:01:00Z"
    }
  ],
  "next_cursor": "<NEXT_CURSOR>"
}
```

URL-encode the actual returned cursor and send it with the same list parameters. Do not use the illustrative token below. Continue until `next_cursor` is null.

**GET https://engine.example.com/namespaces/acme/collections/incident-logs/files?prefix=/incidents/&limit=1&cursor=<URL_ENCODED_NEXT_CURSOR>**

```http
GET /namespaces/acme/collections/incident-logs/files?prefix=/incidents/&limit=1&cursor=<URL_ENCODED_NEXT_CURSOR> HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
```

List cursors expire after one hour. A cursor belongs to its original request and key. An expired or mismatched cursor returns `400 invalid_cursor`; restart from the first page.

## Paginate Search

Search returns `results` and its own `next_cursor`. Send the returned cursor in the next JSON body. Keep the query, mode, interpretation, filter, principals, result type, and limit unchanged.

**POST https://engine.example.com/namespaces/acme/collections/incident-logs:search**

```http
POST /namespaces/acme/collections/incident-logs:search HTTP/1.1
Host: engine.example.com
Authorization: Bearer <GRAPHON_ENGINE_API_KEY>
Content-Type: application/json

{
  "query": "checkout",
  "mode": "hybrid",
  "limit": 10,
  "cursor": "<NEXT_CURSOR>"
}
```

Search cursors last 40 minutes and preserve the search’s index generation. Treat every cursor as opaque. Do not share cursors across keys or reuse them for a different search.

The default `file` result type returns a file on one page only. `next_cursor: null` ends traversal. A fresh first-page request can include newly indexed content. See [Pagination and idempotency](/engine/reference/pagination) for the complete conventions.

## Keep access separate

> **Filters select data**
>
> A caller can omit a filter. Use enforced access rules and trusted principals for per-reader authorization. Apply those rules before content reaches a Search result or an answer.

See [Apply access rules](/engine/guides/access-rules) for a complete example.
## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
