> ## Documentation Index
> Fetch the complete documentation index at: https://docs.repost.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Search and filters

> The query grammar for searching indexed history, the filter subset for live streams, and how cursor pagination behaves.

Repost has **two** query surfaces. Using one's syntax against the other is the most common agent mistake.

| Commands                           | Reads from                                          | Query style                    |
| ---------------------------------- | --------------------------------------------------- | ------------------------------ |
| `events search`, `forwards search` | the **indexed store** (searchable history)          | a full field + boolean grammar |
| `expect`, `tail`                   | the **live observe stream** (events as they arrive) | a small fixed-field filter     |

`repost docs search` prints a short cheatsheet; this page is the full reference.

## Search indexed history

The text after `events search` / `forwards search` is a query over indexed fields. Scope with the `--bucket` / `--forwarder` flags — don't put identifiers in the query (see [Scope is enforced](#scope-is-enforced)).

### Fields for `events search`

| Field                     | Matches                                                                                    |
| ------------------------- | ------------------------------------------------------------------------------------------ |
| `method`                  | HTTP method — `method:POST`                                                                |
| `path`                    | Request path. `path:` is rewritten to the indexed `path_original` — `path:/stripe/webhook` |
| `response_status`         | Numeric HTTP response code — `response_status:500`                                         |
| `received_at`             | Ingest time (also the sort and `--since`/`--until` window field)                           |
| `bucket_id`, `event_id`   | Stable identifiers (prefer `--bucket` for scoping)                                         |
| `request.*`, `response.*` | Any JSON field in the captured body — `request.type:charge.refunded`                       |

A **bare word** with no `field:` prefix searches the default fields only — `path_original`, `request.body`, `response.body` — not every field.

<Warning>
  Don't use `status:` in a query. The query layer rewrites it to a nested `response.status` field that won't match the indexed response code. Use **`response_status:`** for the HTTP code on `events search`, and **`--failed`** to filter failed deliveries on `forwards search`.
</Warning>

### Operators

`AND`, `OR`, `NOT`, parentheses, and `*` / `?` wildcards are supported:

```bash theme={null}
repost events search 'method:POST AND path:/stripe/* AND NOT response_status:200' \
  --bucket stripe-prod --since 30m --json
```

Wildcards run against **tokenized** terms for text fields like `path_original`, so `path:/stripe/*` matches on path tokens, not the raw literal string.

### Scope is enforced

The query is wrapped in mandatory organization and resource filters server-side:

* `org_id:` in a query is rejected with `validation_failed`.
* `bucket_id:` for a bucket you don't own is rejected.
* `forwarder_id:` is stripped — use the `--forwarder` flag instead.

### Filters for `forwards search`

Use flags for the common cases rather than query fields:

| Flag                  | Filters by                                            |
| --------------------- | ----------------------------------------------------- |
| `--forwarder` / `-f`  | Forwarder ID, or name (name also requires `--bucket`) |
| `--bucket` / `-b`     | Bucket slug or ID                                     |
| `--event`             | A single `event_id`                                   |
| `--failed`            | Failed deliveries — the reliable failure filter       |
| `--since` / `--until` | Time window (RFC3339 or a duration like `1h`)         |

<Note>
  `--failed` is the correct way to find failures. A free-text `status:FAILED` is rewritten and will **not** match the delivery status field. Default bare-word search covers `path_original`, `target_url`, `request.body`, `response.body`, and `error_message`.
</Note>

## Filter the live stream

`expect` and `tail` watch events **as they arrive**, before they're indexed. They take a small, exact-match filter — not the search grammar above.

| Flag              | Matches                                                                             |
| ----------------- | ----------------------------------------------------------------------------------- |
| `--bucket` / `-b` | Bucket slug or ID (required)                                                        |
| `--path`          | Path, shell-glob style (`--path '/stripe/*'`)                                       |
| `--method`        | HTTP method (case-insensitive)                                                      |
| `--filter`        | A `field:value` term over `method`, `path`, `content_type`, `event_id`, `bucket_id` |

Wildcards in `--path` use shell-glob matching (`*`, `?`, `[…]`) against the literal path — different from the tokenized wildcards of indexed search. Usage is covered in [Wait for events](/agents/wait-for-events).

## Page with cursors

`events search`, `forwards search`, and the list commands paginate with `--cursor`. Read the cursor off each response and pass it back to get the next page.

* **Forward-only.** Each response carries `next_cursor`; there is no backward cursor. Stop when `has_more` is `false`.
* **Bound to the query and window.** The cursor encodes a hash of the exact query plus `--since`/`--until`. Change the query, bucket, forwarder, or window and the old cursor is rejected with `validation_failed` — *"stale or invalid cursor; re-run the search."*
* **Replayable, not single-use.** A cursor has no expiry or one-time semantics — re-sending it returns the same page. Treat it as "page N of *this exact* query," not a token you can only spend once.

```bash theme={null}
page=$(repost events search 'method:POST' --bucket stripe-prod --since 1h --limit 100 --json)
while :; do
  echo "$page" | jq -c '.data.items[]'
  [ "$(echo "$page" | jq -r '.data.has_more')" = "true" ] || break
  cursor=$(echo "$page" | jq -r '.data.next_cursor')
  page=$(repost events search 'method:POST' --bucket stripe-prod --since 1h --limit 100 --cursor "$cursor" --json)
done
```

## Continue

<Columns cols={3} className="gap-y-4">
  <Card title="Diagnose a webhook" icon="search-check" href="/agents/diagnose-webhooks" cta="Investigate" arrow="true">
    Put bounded search and the delivery chain to work on a real failure.
  </Card>

  <Card title="Wait for events" icon="timer" href="/agents/wait-for-events" cta="Use live filters" arrow="true">
    `expect` and `tail` against the live stream.
  </Card>

  <Card title="Discovery" icon="compass" href="/agents/discovery" cta="Learn the surface" arrow="true">
    Pull the manifest and per-command schemas from the binary.
  </Card>
</Columns>
