---
title: "Execute Public Retriever"
method: POST
path: "/v1/public/retrievers/{public_name}/execute"
tags: ["Public Retriever API"]
---

# Execute Public Retriever

`POST /v1/public/retrievers/{public_name}/execute`

Execute a published retriever (public endpoint).

**Authentication:**
- API key is OPTIONAL for public retrievers
- Supports: no key, prk_ keys (deprecated), or ret_sk_ keys
- If password-protected, requires `X-Retriever-Password` header

**Rate Limiting:**
- Subject to per-retriever rate limits (per minute/hour/day)
- May also have IP-based rate limits

**Response:**
- Only returns fields specified in `exposed_fields` configuration
- Internal metadata is stripped from results
- Includes `execution_id` for interaction tracking
- Presigned URLs returned by default (return_presigned_urls=true) for media rendering

**Example (no API key - recommended for public access):**
```bash
curl -X POST "https://api.mixpeek.com/v1/public/retrievers/video-search/execute" \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": {"query": "red car"},
    "pagination": {"method": "offset", "page_number": 1, "page_size": 10}
  }'
```

**Example with ret_sk_ key (for SDK/programmatic access):**
```bash
curl -X POST "https://api.mixpeek.com/v1/public/retrievers/video-search/execute" \
  -H "X-Public-API-Key: ret_sk_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "inputs": {"query": "red car"},
    "pagination": {"method": "offset", "page_number": 1, "page_size": 10}
  }'
```

## Path parameters

- `public_name` string, required — Public name of the published retriever

## Query parameters

- `return_presigned_urls` boolean — Generate fresh presigned download URLs for all blobs with S3 storage. Default: True for public retrievers to enable media rendering. Set to False if you only need metadata without URLs.

## Headers

- `X-Public-API-Key` string, nullable
- `X-Retriever-Password` string, nullable

## Request body

- RetrieverExecutionRequest — Request payload for executing a retriever. Executes a predefined retriever with runtime inputs. The retriever uses the collections it was created with - collection overrides are not supported at execution time to ensure feature_uri and schema validation integrity. All filtering, pagination, and result shaping is handled by the individual stages based on the inputs provided. Use Cases: - Execute retriever with its configured collections - Pass inputs that stages use to determine filtering/pagination behavior Design Philosophy: - Retrievers are validated at creation time against their collections - Feature URIs, input schemas, and stage configs are tightly coupled to collections - Filters, limits, and offsets are NOT top-level request fields - These are handled by stages when they receive inputs - Example: A stage might read {INPUT.top_k} to determine result limit Examples: Simple query: {"inputs": {"query": "AI", "top_k": 50}} Different inputs for stage behavior: {"inputs": { "query": "machine learning", "top_k": 100, "min_score": 0.7, "published_after": "2024-01-01" }}
  - `inputs` object — Runtime inputs for the retriever mapped to the input schema. Keys must match the retriever's input_schema field names. Values depend on field types (text, vector, filters, etc.). REQUIRED unless all retriever inputs have defaults. Common input keys: - 'query': Text search query - 'embedding': Pre-computed vector for search - 'top_k': Number of results to return - 'min_score': Minimum relevance threshold - Any custom fields defined in input_schema **Template Syntax** (Jinja2): Namespaces (uppercase or lowercase): - `INPUT` / `input`: Query inputs (e.g., `{{INPUT.query}}`) - `DOC` / `doc`: Document fields (e.g., `{{DOC.payload.title}}`) - `CONTEXT` / `context`: Execution context - `STAGE` / `stage`: Stage configuration - `SECRET` / `secret`: Vault secrets (e.g., `{{SECRET.api_key}}`) Accessing Data: - Dot notation: `{{DOC.payload.metadata.title}}` - Bracket notation: `{{DOC.payload['special-key']}}` - Array index: `{{DOC.items[0]}}`, `{{DOC.tags[2]}}` - Array first/last: `{{DOC.items | first}}`, `{{DOC.items | last}}` Array Operations: - Iterate: `{% for item in DOC.tags %}{{item}}{% endfor %}` - Extract key: `{{DOC.items | map(attribute='name') | list}}` - Join: `{{DOC.tags | join(', ')}}` - Length: `{{DOC.items | length}}` - Slice: `{{DOC.items[:5]}}` Conditionals: - If: `{% if DOC.status == 'active' %}...{% endif %}` - If-else: `{% if DOC.score > 0.8 %}high{% else %}low{% endif %}` - Ternary: `{{'yes' if DOC.enabled else 'no'}}` Built-in Functions: `max`, `min`, `abs`, `round`, `ceil`, `floor` Custom Filters: `slugify` (URL-safe), `bool` (truthy coercion), `tojson` (JSON encode) S3 URLs: Internal S3 URLs (s3://bucket/key) are automatically presigned when accessed via DOC namespace.
  - `filters` object, nullable — Optional ad-hoc filters applied at execution time. Merged (AND) with any filters already defined in the retriever's stages. Uses the standard LogicalOperator format: {"AND": [{"field": "brand", "operator": "eq", "value": "Acme"}]}. Supports operators: eq, ne, in, nin, gt, gte, lt, lte, contains, exists, is_null.
  - `pagination` union — Pagination strategy configuration. When omitted entirely, defaults to cursor-based pagination sized to the pipeline's declared final_top_k (author intent); pipelines that declare no final_top_k default to limit=10. Any explicit pagination (or the deprecated body 'limit') is honored exactly. IMPORTANT: Pagination params do NOT support template variables ({{INPUT.x}} or {{DOCUMENT.x}}). Pagination is a request-level parameter for slicing results, separate from pipeline business logic. Pass cursor/limit values directly from your client code. Cursor values come from the previous response's pagination.cursor field. Supported Methods: - CURSOR (default): Best for infinite scroll, stateless, opaque token - KEYSET: Most efficient, requires stable sort, stateless - OFFSET: Traditional page numbers, can have drift issues - SCROLL: Server-side state, best for bulk exports Use CURSOR for: - Infinite scroll UIs (mobile apps, feeds, timelines) - Real-time updates where consistency matters - When you can't jump to arbitrary pages Use KEYSET for: - Maximum performance with large result sets - Stable sort fields (e.g., score DESC, id ASC) - When you need truly stateless pagination Use OFFSET for: - Traditional page UIs with page numbers - When users need to jump to specific pages - Smaller result sets where drift is acceptable Use SCROLL for: - Bulk exports or processing large datasets - When you need to iterate through all results - Background jobs with progress tracking Example (cursor - first page): {"method": "cursor", "limit": 20, "cursor": null} Example (cursor - next page, using cursor from previous response): {"method": "cursor", "limit": 20, "cursor": "eyJvZmZzZXQiOjIwfQ=="} Example (offset): {"method": "offset", "page_size": 25, "page_number": 2} Example (keyset): {"method": "keyset", "limit": 20, "after": {"score": 0.73, "id": "doc_20"}}
    - OffsetPaginationParams — Offset-based pagination using page number sizing. Best for: Traditional page UIs with page number navigation How it works: - Uses page numbers (1, 2, 3...) and page size - Calculates offset as: (page_number - 1) * page_size - Simple and familiar for users - Can jump to any page directly Tradeoffs: - Can have "page drift" if data changes between requests - Example: Items added/deleted causes duplicates or gaps - Less efficient for large offsets (database must skip N rows) Use when: - Building traditional page-numbered UIs - Users need to jump to specific pages - Result set is relatively stable - Working with smaller datasets Example: Page 1: {"method": "offset", "page_size": 25, "page_number": 1} Page 2: {"method": "offset", "page_size": 25, "page_number": 2}
      - `method` 'offset' — Constant identifying offset pagination (REQUIRED).
      - `page_size` integer — Number of documents per page (REQUIRED). Default: 10.
      - `page_number` integer — 1-based page index to retrieve (REQUIRED). Default: 1.
    - CursorPaginationParams — Cursor-based pagination referencing last seen position. Best for: Infinite scroll UIs, mobile apps, real-time feeds How it works: - First request: cursor=null - Response includes next cursor token - Next request: pass cursor from previous response - Stateless: no server-side state - Consistent: no duplicates/gaps even with concurrent writes Use when: - Building infinite scroll interfaces - Users scroll through results sequentially - You need consistency across pages - You don't need to jump to arbitrary pages Example flow: 1. Request: {"method": "cursor", "limit": 20, "cursor": null} 2. Response: {"documents": [...], "pagination": {"cursor": "abc123", "has_next": true}} 3. Request: {"method": "cursor", "limit": 20, "cursor": "abc123"}
      - `method` 'cursor' — Constant identifying cursor pagination (REQUIRED).
      - `limit` integer — Maximum number of documents to return per page (REQUIRED). Default: 10.
      - `cursor` string, nullable — Opaque base64 cursor from previous response (OPTIONAL). null for first page, then use cursor from response.pagination.cursor
    - ScrollPaginationParams — Scroll-style pagination maintaining server-side context for TTL. Best for: Bulk exports, batch processing, iterating through all results How it works: - Server maintains a snapshot of results - First request: scroll_id=null, returns scroll_id - Subsequent requests: use scroll_id from response - Context expires after scroll_ttl seconds - Consistent view of data (point-in-time snapshot) Tradeoffs: - Requires server-side state (memory/cache) - TTL means sessions can expire - Not suitable for long-lived sessions - Good for background jobs, not user-facing UIs Use when: - Exporting large datasets - Batch processing all results - Background jobs iterating through results - You need consistent point-in-time view Example flow: 1. Request: {"method": "scroll", "limit": 100, "scroll_id": null} 2. Response: {"documents": [...], "scroll_id": "xyz789", "has_next": true} 3. Request: {"method": "scroll", "limit": 100, "scroll_id": "xyz789"}
      - `method` 'scroll' — Constant identifying scroll pagination (REQUIRED).
      - `limit` integer — Number of documents to fetch per scroll page (REQUIRED). Default: 100.
      - `scroll_id` string, nullable — Server-issued scroll session identifier (OPTIONAL). null for first request, then use scroll_id from response
      - `scroll_ttl` integer — Seconds to keep scroll context alive (REQUIRED). Default: 300 (5 minutes).
    - KeysetPaginationParams — Stateless keyset pagination relying on last seen sort key. Best for: High-performance pagination, large result sets, stable sorting How it works: - Uses actual field values as pagination markers - Database can use indexes efficiently (WHERE score < 0.73) - No offset calculation or server state - Requires deterministic sort order (e.g., score DESC, id ASC) - Most efficient pagination method Requirements: - Results must be sorted consistently - Sort fields must be in the "after" marker - Example: sorted by (score DESC, id ASC) → after: {score: 0.73, id: "doc_20"} Advantages: - No server-side state (truly stateless) - Consistent even with concurrent writes - Database can use indexes (fast for large datasets) - No offset performance degradation Use when: - You have stable, deterministic sort fields - Working with large result sets (10k+ docs) - Maximum performance is critical - You need infinite scroll with best efficiency Example flow: 1. Request: {"method": "keyset", "limit": 20, "after": null} 2. Response: {"documents": [...], "next_cursor": {"score": 0.85, "id": "doc_20"}} 3. Request: {"method": "keyset", "limit": 20, "after": {"score": 0.85, "id": "doc_20"}}
      - `method` 'keyset' — Constant identifying keyset pagination (REQUIRED).
      - `limit` integer — Maximum number of documents to return per page (REQUIRED). Default: 10.
      - `after` object, nullable — Last seen keyset marker from previous response (OPTIONAL). Must include all sort fields. Example: {'score': 0.73, 'id': 'doc_20'}. null for first page, then use next_cursor from response
  - `limit` integer, nullable — DEPRECATED alias for the pagination page size — prefer 'pagination' (e.g. {"method": "cursor", "limit": 100}). Previously accepted-and-IGNORED: results silently capped at the default page size (10) regardless of the value, and out-of-range values didn't even 422 (FRUSTRATIONS 2026-07-23). Now: when 'pagination' is absent, 'limit' is honored as the default cursor pagination's page size; when both are provided and disagree, pagination wins and a top-level response warning names the conflict.
  - `stream` boolean — Enable streaming execution to receive real-time stage updates via Server-Sent Events (SSE). NOT REQUIRED - defaults to False for standard execution. When stream=True: - Response uses text/event-stream content type - Each stage completion emits a StreamStageEvent - Events include: stage_start, stage_complete, stage_error, execution_complete - Clients receive intermediate results and statistics as stages execute - Useful for progress tracking, debugging, and partial result display When stream=False (default): - Response returns after all stages complete - Returns a single RetrieverExecutionResponse with final results - Lower overhead for simple queries Use streaming when: - You want to show real-time progress to users - You need to display intermediate results - Pipeline has many stages or long-running operations - Debugging or monitoring pipeline performance Example streaming client (JavaScript): ```javascript const eventSource = new EventSource('/v1/retrievers/ret_123/execute?stream=true'); eventSource.onmessage = (event) => { const stageEvent = JSON.parse(event.data); if (stageEvent.event_type === 'stage_complete') { console.log(`Stage ${stageEvent.stage_name} completed`); console.log(`Documents: ${stageEvent.documents.length}`); } }; ``` Example streaming client (Python): ```python import requests response = requests.post('/v1/retrievers/ret_123/execute', json={'inputs': {...}, 'stream': True}, stream=True) for line in response.iter_lines(): if line.startswith(b'data: '): event = json.loads(line[6:]) print(f"Stage {event['stage_name']}: {event['event_type']}") ```
  - `expand` string[], nullable — OPTIONAL. List of fields containing document IDs to resolve inline. Referenced documents are fetched and attached under an '_expanded' key in each result document. Supports dot-notation for nested fields (e.g., 'items.product_id'). Max 50 unique references per request. Depth is limited to 1 (no recursive expansion).
  - `skip_cache` boolean — OPTIONAL. Bypass stage result cache for this execution. When True, all stages execute fresh without cache lookup. Useful after corpus updates, retriever config changes, or engine deploys. Results are still written to cache for future requests.
  - `return_presigned_urls` boolean — Generate presigned URLs for S3-backed blobs and url-shaped fields in result documents. Also accepted as a `return_presigned_urls` query parameter; if either source is true, presigning is enabled.
  - `return_vectors` boolean — Include vector embeddings in result documents. Also accepted as a `return_vectors` query parameter; if either source is true, vectors are returned.
  - `write_token` string, nullable — OPTIONAL. Pass the `write_token` returned by a prior direct upsert (options.write_token=true) to get read-your-writes consistency: the read is routed to the primary shard, where your just-written document is immediately searchable, instead of an eventually-consistent replica that can lag several seconds behind. Omit for normal (eventual) reads.

## Response `200`

Successful Response

- unknown

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `403` — Forbidden
- `404` — Not Found
- `422` — Validation Error
- `500` — Internal Server Error

---

[API](https://skmtc.net/mixpeek/apis/mixpeek-api.md) · [All operations](https://skmtc.net/mixpeek/apis/mixpeek-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/mixpeek/mixpeek-api/versions/23e05292e326/schema)
