---
title: Search collection
description: Retrieve ranked files or passages with source evidence from one collection.
doc_version: 0.1.0-preview
last_updated: 2026-09-14
---

# Search collection

`POST /namespaces/{namespace}/collections/{collection}:search`

Retrieve ranked files or passages with source evidence from one collection.

**Permission:** Cluster key, or a scoped key with search on this collection.

[API key types and authentication](/engine/reference/authentication.md).

Search returns evidence and never generates an answer. Use Query for a cited answer.

semantic is the default mode. The corresponding processing flag must be enabled.

Empty collections return 200 with no results. Indexing with no ready files returns collection_not_ready. A failed collection returns no results and a warning.

Send principals only when access_control is enforced. No key bypasses the access rules.

Use next_cursor with the same request and key. Search cursors expire after 40 minutes. sort changes the order within each page, not the relevance ranks.

## Example request

```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": "database timeout",
  "mode": "semantic",
  "limit": 10
}
```

## Path parameters

### `namespace`

**string · required**

Namespace name or ns_ ID. It must be visible to this key.

### `collection`

**string · required**

Collection name or col_ ID within the namespace. It must be visible to this key.

## Request body

### `cursor`

**string · optional · nullable**

Opaque continuation token from next_cursor. Keep the same key, filters, and other request values. Omit it for the first page.

### `filter`

**FilterClause · optional · nullable**

Structured file selection using built-in or metadata fields. Combine clauses with and, or, and not. Filters select data and do not grant or restrict key access.

- Maximum depth: 8
- Maximum clauses: 100
- An in list holds 1–100 values.

#### Comparison

Compare one built-in or metadata field.

##### `filter.field`

**string · required**

path, content_type, bytes, created_at, updated_at, status, or metadata.<key>. Metadata keys have 1–256 characters.

##### `filter.op`

**string · required**

Comparison operator. Strings support eq, neq, prefix, and in. bytes supports numeric comparisons and in. Timestamps support comparisons. status supports eq, neq, and in.

- `eq`: Equal.
- `neq`: Not equal.
- `gt`: Greater than.
- `gte`: Greater than or equal.
- `lt`: Less than.
- `lte`: Less than or equal.
- `prefix`: String starts with this value.
- `in`: Equal to one value in a nonempty array.

##### `filter.value`

**JSON scalar | array<JSON scalar> · required**

Value of the correct type for the field. bytes uses non-negative integers. Timestamps need an ISO 8601 timezone. in takes an array. Metadata equality accepts string, number, boolean, or null.

#### All clauses

##### `filter.and`

**array<FilterClause> · required**

Nonempty list of clauses that must all match. Each entry uses this same FilterClause grammar.

#### Any clause

##### `filter.or`

**array<FilterClause> · required**

Nonempty list of clauses where at least one must match. Each entry uses this same FilterClause grammar.

#### Negated clause

##### `filter.not`

**FilterClause · required**

One clause that must not match. It uses this same FilterClause grammar.

### `interpretation`

**string · optional**

literal uses the supplied search text. natural_language can derive search text and filters from a sentence. It does not generate an answer.

Default: `"literal"`.

- `literal`: Use the supplied search text.
- `natural_language`: Interpret a sentence as search text and filters.

### `limit`

**integer · optional**

Maximum results in this page. Default 10, minimum 1, maximum 100.

Default: `10`.

- Minimum: 1
- Maximum: 100

### `mode`

**string · optional**

keyword finds lexical matches. semantic retrieves by meaning without a caller-supplied embedding. The corresponding collection processing flag must be enabled.

Default: `"semantic"`.

- `keyword`: Lexical retrieval.
- `semantic`: Meaning-based retrieval.

### `principals`

**array<string> · optional · nullable**

End-user and group identifiers supplied by your server. Required on enforced collections and invalid when access control is off. An empty list gives no results. Maximum 4,096 entries, each at most 256 UTF-8 bytes.

### `query`

**string · required**

Search text. Must contain a non-space character. Maximum 32,000 characters.

- Minimum characters: 1
- Maximum characters: 32000

### `result_unit`

**string · optional**

file groups evidence by source file. passage returns individual matching passages.

Default: `"file"`.

- `file`: Group matching passages by source file.
- `passage`: Return individual matching passages.

### `sort`

**array<object> · optional**

Order results within each page. Use at most four distinct fields, in priority order. Relevance rank remains unchanged.

#### `sort[].field`

**string · required**

Field used to sort the results within each page. Metadata fields are not sort fields.

- `score`: Relevance score.
- `path`: Logical file path.
- `content_type`: File MIME type.
- `bytes`: Declared file size. Unknown sizes sort last.
- `created_at`: File creation time.
- `updated_at`: File update time.

#### `sort[].order`

**string · required**

asc sorts from lowest to highest. desc sorts from highest to lowest.

- `asc`: Lowest to highest.
- `desc`: Highest to lowest.

## Responses

### 200 · Success

Ranked evidence. Timing and score values are illustrative.

Content type: `application/json`.

#### Response headers

##### `x-request-id`

**string · required**

Request correlation ID. Retain it when investigating a failed or unexpected request.

```json
{
  "request_id": "req_example",
  "index_generation": "gen_example",
  "execution": {
    "mode": "semantic",
    "interpretation": "literal",
    "stages": [
      "semantic"
    ]
  },
  "results": [
    {
      "file_id": "fil_01K6Q6N7D8E9F0G1H2J3K4M5N6",
      "path": "/reports/incident.txt",
      "content_type": "text/plain",
      "rank": 1,
      "score": 0.81,
      "matched_by": [
        "semantic"
      ],
      "evidence": [
        {
          "kind": "text",
          "text": "Checkout requests stalled because the database connection pool was exhausted.",
          "location": {
            "char_start": 0,
            "char_end": 77
          }
        }
      ]
    }
  ],
  "timing_ms": {
    "retrieval": 34,
    "total": 47
  },
  "warnings": [],
  "next_cursor": null
}
```

#### Response fields

##### `execution`

**object · required**

Modes and stages used by this request.

###### `execution.interpretation`

**string · required**

Interpretation used for the search text.

- `literal`: Use the supplied search text.
- `natural_language`: Interpret a sentence as search text and filters.

###### `execution.mode`

**string · required**

Retrieval mode used for this search.

- `keyword`: Lexical retrieval.
- `semantic`: Meaning-based retrieval.

###### `execution.stages`

**array<string> · required**

Retrieval stages used to produce the result. Current stages use the selected search mode.

- `keyword`: Lexical retrieval.
- `semantic`: Meaning-based retrieval.

##### `index_generation`

**string · required · nullable**

Opaque identifier for the searchable generation. It changes when indexed data changes. Null means that no searchable generation exists.

##### `next_cursor`

**string · required · nullable**

Token for the next page, or null when this result has no next page. Do not parse or modify the token.

##### `request_id`

**string · required**

Correlation ID for this request, also available in x-request-id.

##### `results`

**array<object> · required**

Ranked files or passages with source evidence. An empty array means there are no matching results.

###### `results[].content_type`

**string · required**

MIME type of the file, such as text/plain, application/pdf, or video/mp4.

###### `results[].evidence`

**array<object> · required**

Matching source excerpts with their positions, when available.

###### `results[].evidence[].kind`

**string · required**

Form of the extracted evidence, such as text, transcript, OCR, or a page.

- `text`: Extracted text.
- `transcript`: Transcript from audio or video.
- `ocr`: Text recognized from an image or document page.
- `json_path`: Evidence at a JSON path.
- `page`: Evidence from a document page.
- `image_region`: Evidence from a region of an image.

###### `results[].evidence[].location`

**object · optional · nullable**

Position of this evidence within the source. The fields depend on its location type. Omitted when no position is available.

###### TimeSpan

###### `results[].evidence[].location.end_ms`

**integer · required**

End of the source excerpt, in milliseconds from the beginning of the audio or video.

###### `results[].evidence[].location.start_ms`

**integer · required**

Start of the source excerpt, in milliseconds from the beginning of the audio or video.

###### Page

###### `results[].evidence[].location.bbox`

**array<number> · optional · nullable**

Optional bounding box coordinates for a region on the referenced page.

###### `results[].evidence[].location.page`

**integer · required**

Page number identifying the evidence in the source.

###### JsonPath

###### `results[].evidence[].location.json_path`

**string · required**

JSON path locating the evidence within a structured source.

###### CharSpan

###### `results[].evidence[].location.char_end`

**integer · required**

End character offset of the evidence within extracted text.

###### `results[].evidence[].location.char_start`

**integer · required**

Start character offset of the evidence within extracted text.

###### `results[].evidence[].text`

**string · required**

Extracted source text supporting this match or citation.

###### `results[].file_id`

**string · required**

ID of the file that contains this result.

###### `results[].matched_by`

**array<string> · required**

Retrieval modes that contributed this match.

- `keyword`: Lexical retrieval.
- `semantic`: Meaning-based retrieval.

###### `results[].path`

**string · required**

Logical path of the matching file within the collection.

###### `results[].rank`

**integer · required**

One-based relevance rank. Custom sorting does not change this value.

###### `results[].score`

**number · required**

Ranking value for this result. It is not a confidence percentage.

##### `timing_ms`

**object · required**

Measured retrieval and total durations in milliseconds.

###### `timing_ms.retrieval`

**integer · required**

Time spent retrieving matches, in milliseconds.

###### `timing_ms.total`

**integer · required**

Total time for the search operation, in milliseconds.

##### `warnings`

**array<object> · required**

Nonfatal conditions that help explain the result, such as every file failing to index.

###### `warnings[].code`

**string · required**

Machine-readable explanation of a nonfatal retrieval condition.

###### `warnings[].message`

**string · required**

Human-readable description of the condition.

## Errors

[Error format and retry guidance](/engine/reference/errors.md).

### 400 · `invalid_request`

A field, path, parameter, or conditional request rule is invalid.

Correct the request. Unknown fields are rejected.

```json
{
  "error": {
    "code": "invalid_request",
    "message": "A field, path, parameter, or conditional request rule is invalid.",
    "request_id": "req_example",
    "retryable": false,
    "details": {}
  }
}
```

### 400 · `invalid_filter`

A filter uses an unsupported field, operator, value, or nesting structure.

Use the documented filter grammar and field-specific value types.

```json
{
  "error": {
    "code": "invalid_filter",
    "message": "A filter uses an unsupported field, operator, value, or nesting structure.",
    "request_id": "req_example",
    "retryable": false,
    "details": {}
  }
}
```

### 400 · `invalid_cursor`

The cursor expired or does not belong to this request and key.

Restart from the first page. Preserve the same key, filters, and request values when continuing.

```json
{
  "error": {
    "code": "invalid_cursor",
    "message": "The cursor expired or does not belong to this request and key.",
    "request_id": "req_example",
    "retryable": false,
    "details": {}
  }
}
```

### 401 · `unauthenticated`

The API key is missing, invalid, or revoked.

Send an active key in Authorization: Bearer or X-API-Key.

```json
{
  "error": {
    "code": "unauthenticated",
    "message": "The API key is missing, invalid, or revoked.",
    "request_id": "req_example",
    "retryable": false,
    "details": {}
  }
}
```

### 403 · `forbidden`

The key can see the resource but lacks permission for this operation.

Use a key with the required action or scope kind.

```json
{
  "error": {
    "code": "forbidden",
    "message": "The key can see the resource but lacks permission for this operation.",
    "request_id": "req_example",
    "retryable": false,
    "details": {}
  }
}
```

### 404 · `not_found`

The resource is absent, deleted, or outside this key’s scope.

Check the identifier and the key’s namespace and collection scope.

```json
{
  "error": {
    "code": "not_found",
    "message": "The resource is absent, deleted, or outside this key’s scope.",
    "request_id": "req_example",
    "retryable": false,
    "details": {}
  }
}
```

### 409 · `collection_not_ready`

The collection cannot serve this retrieval request yet.

Read retryable and details.retry_after_seconds. If processing failed, inspect file errors and correct the source.

```json
{
  "error": {
    "code": "collection_not_ready",
    "message": "The collection cannot serve this retrieval request yet.",
    "request_id": "req_example",
    "retryable": true,
    "details": {
      "retry_after_seconds": 30
    }
  }
}
```

### 413 · `request_too_large`

The JSON request body exceeds 1,048,576 bytes.

Reduce the JSON body. Use upload or a URI source for larger file content.

```json
{
  "error": {
    "code": "request_too_large",
    "message": "The JSON request body exceeds 1,048,576 bytes.",
    "request_id": "req_example",
    "retryable": false,
    "details": {}
  }
}
```

### 503 · `temporarily_unavailable`

A dependency, cluster readiness condition, or capacity limit prevents this operation.

Inspect retryable and details. Retry only when permitted, preserving the idempotency key for the same write.

```json
{
  "error": {
    "code": "temporarily_unavailable",
    "message": "A dependency, cluster readiness condition, or capacity limit prevents this operation.",
    "request_id": "req_example",
    "retryable": true,
    "details": {}
  }
}
```

### 500 · `internal_error`

An unexpected server failure prevented this request from completing.

Retain x-request-id for investigation. Follow retryable before retrying a write.

```json
{
  "error": {
    "code": "internal_error",
    "message": "An unexpected server failure prevented this request from completing.",
    "request_id": "req_example",
    "retryable": false,
    "details": {}
  }
}
```

## Other request languages

### cURL

```bash
curl -sS -X POST "$GRAPHON_ENGINE_URL/namespaces/acme/collections/incident-logs:search" \
  -H "Authorization: Bearer $GRAPHON_ENGINE_API_KEY" \
  -H 'Content-Type: application/json' \
  --data-raw '{
  "query": "database timeout",
  "mode": "semantic",
  "limit": 10
}'
```

### Python

```python
import json
import os
import urllib.request

request = urllib.request.Request(
    os.environ["GRAPHON_ENGINE_URL"] + "/namespaces/acme/collections/incident-logs:search",
    data=json.dumps({"query": "database timeout", "mode": "semantic", "limit": 10}).encode("utf-8"),
    headers={
        "Authorization": "Bearer " + os.environ["GRAPHON_ENGINE_API_KEY"],
        "Content-Type": "application/json",
    },
    method="POST",
)
with urllib.request.urlopen(request) as response:
    print(response.read().decode())
```

### JavaScript

```javascript
const response = await fetch(process.env.GRAPHON_ENGINE_URL + "/namespaces/acme/collections/incident-logs:search", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.GRAPHON_ENGINE_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({"query":"database timeout","mode":"semantic","limit":10}),
});
console.log(response.status, await response.text());
```

## Sitemap

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