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).
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 | Receive 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 only the default fields (path_original, request.body, response.body), not every field.
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.
Operators#
AND, OR, NOT, parentheses, and * / ? wildcards are supported:
repost events search 'method:POST AND path:/stripe/* AND NOT response_status:200' \
--bucket stripe-prod --since 30m --jsonWildcards 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 withvalidation_failed.bucket_id:for a bucket you don't own is rejected.forwarder_id:is stripped. Use the--forwarderflag 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) |
--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.
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.
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 whenhas_moreisfalse. - 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 withvalidation_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.
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