---
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 and Query 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.

**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. |
| `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. Unsupported fields, operators, or value combinations return `400 invalid_filter`. Its details can name the field or operator.

## Sort Search results

Search supports up to four distinct sort fields: `score`, `path`, `content_type`, `bytes`, `created_at`, and `updated_at`. Each sort item requires `order: "asc"` or `"desc"`.

**Example sort field in a Search body**

```json
{
  "sort": [
    {
      "field": "path",
      "order": "asc"
    }
  ]
}
```

Sort applies to the rows of each returned page. It does not globally sort the entire matching corpus. `rank` remains the relevance rank. Files with unknown sizes sort after known sizes for a bytes sort.

## 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",
      "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, sort, result unit, 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": "semantic",
  "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 unit 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 Query answer.

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

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