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

# HTTP search and metadata

> HTTP routes and filters for finding recorded execution.

Find a request with `GET /v1/traces`, then use its `trace_id` to
[read calls and values](https://docs.vexlo.ai/reference/http-traces.md). Search by an identifier you already have,
such as a tag value, before widening to a service and time window.

## Route index

All routes below use the server's base URL. The versioned API prefix is `/v1`.

| Method and route | Permission | Response / reference |
| - | - | - |
| `GET /v1/capabilities` | No token | API/version, features, authentication mode and limits |
| `GET /v1/whoami` | Read or ingest | Credential role and scope |
| `GET /v1/traces` | Read | Trace summaries |
| `GET /v1/traces/{id}` | Read | [Recorded calls](https://docs.vexlo.ai/reference/http-traces.md#read-one-request) |
| `GET /v1/traces/{id}/values` | Read | [Selected full values](https://docs.vexlo.ai/reference/http-traces.md#fetch-arguments-results-errors-or-logs) |
| `GET /v1/traces/{id}/related` | Read | [Related executions](https://docs.vexlo.ai/reference/http-traces.md#find-related-requests) |
| `GET /v1/functions` | Read | Function catalog |
| `GET /v1/functions/detail` | Read | Observed callers and callees |
| `GET /v1/functions/examples` | Read | Retained recorded examples |
| `GET /v1/tags` | Read | Tag-key catalog |
| `GET /v1/coverage` | Read | Observed activity and reported record loss |
| `GET /v1/health` | Read | Storage mode, capacity and service health |

The relay uses `POST /v1/records` and `POST /v1/heartbeat` with ingest credentials. Use the
[Python SDK](https://docs.vexlo.ai/instrumentation/python.md) to record application execution and
the [configuration commands](https://docs.vexlo.ai/deployment/configuration.md) to update capture policy through
`PUT /v1/policy`.

## Authentication and common conventions

In bearer-token mode, read routes require `Authorization: Bearer` followed by a read token.
`GET /v1/whoami` accepts
either token role and reports its identity and scope. `GET /v1/capabilities` needs no token.
The web UI's `/config.json` is also unauthenticated.

List routes accept `limit` and `cursor`. The default list limit is `50`, the maximum `500`.
Responses contain `items`, the applied `limit`, and `next_cursor`: a string for another page,
`null` when the page ends the walk. Treat the cursor as opaque. `limit` must be a positive
integer; values above the maximum are clamped. The response reports the applied bound.

Team-scoped listings accept `team` to narrow the token's team set. Requested teams outside
that set yield no matching rows. `environment` accepts comma-separated names; use
`environment_unset=true` for recordings with no environment. Setting both produces
`400 conflicting_filters`. Omitting both applies no environment filter. The tags route accepts
`environment` but ignores `environment_unset`.

Instants use RFC 3339 UTC with millisecond precision. Trace-level durations use integer
milliseconds; call and attempt timings use microseconds. IDs and cursors are opaque.

## Capabilities and identity

`GET /v1/capabilities` returns `server_version`, `api_version`, `features`, `auth_mode` and
`limits`. `auth_mode` is `bearer`, `header_trust` or `none`. Current feature
`in_flight_attempts` means a trace can contain attempts with no duration or slots yet. Limits
report search/step page sizes, values-path bounds, accepted record formats and rate limits.
This bootstrap response contains no team or environment data.

`GET /v1/whoami` returns `role`, `team_ids`, `service_scope` and `environment_scope`. Unpinned
scopes are `null`. Use it to confirm the credential actually presented by the client.

## Find requests

`GET /v1/traces`

| Query parameter | Meaning |
| - | - |
| `service` | Match any comma-separated service name |
| `team`, `environment`, `environment_unset` | Narrow scope as described above |
| `since`, `until` | Inclusive bounds on server first-receipt time, RFC 3339 instants |
| `completeness` | `running`, `abandoned`, `complete` or `partial` |
| `root_status` | Root result: `ok` or `error` |
| `has_error` | `true` or `false`; any failed attempt, including recovered failures |
| `root_function` | Match the entry function's qualified name |
| `function` | Match a function anywhere in the request |
| `duration_min_ms`, `duration_max_ms` | Trace duration bounds in integer milliseconds |
| `tag_key`, `tag_value` | Match a key, a value across keys, or the key/value pair |
| `trace_id` | Direct lookup of up to 100 comma-separated IDs |
| `limit`, `cursor` | Page controls |

Time filtering uses the server's `first_seen_at`, not the SDK's `started_at`. A recording
delivered after an outage therefore falls within its arrival window even when execution began
earlier.

`trace_id` ignores the other search filters. Token team scope still applies, and the response
has no next page. Ordinary results sort by `last_seen_at` descending. A value-only tag search
also returns `matched_tag_keys` so you can see which keys matched.

`error_step_count` counts calls with any failed attempt. A call that fails and then succeeds
still counts once. `has_error=true` can therefore find a recovered failure whose
`root_status` is `ok`.

Rows include `trace_id`, `service`, `team`, `instance_id`, `tags`, `started_at`, `step_count`,
`error_step_count` and recording-loss fields. `root_function` is omitted until known;
`root_status` and `duration_ms` are omitted until the root completes. `environment` is
omitted when it was not recorded.

## Find functions and observed dependencies

| Route | Query parameters | Result |
| - | - | - |
| `GET /v1/functions` | Common scope; `service`, `name`, `limit`, `cursor` | Function rows ordered by `observed_count` descending |
| `GET /v1/functions/detail` | Common scope; required `service` and `name` | Function row plus `observed_callers` and `observed_callees` |
| `GET /v1/functions/examples` | Common scope; required `service` and `name`; `include`, `limit` | Recorded examples; default/max limit `5`, no cursor |

`name` is an exact equality filter. The server applies it after pagination, so an empty
filtered page can still have `next_cursor`. Continue until that cursor
is `null` before concluding that the catalog has no match.

Function rows report `observed_count`, `error_count`, `first_seen_at`, `last_seen_at` and
`is_entry_point`. `observed_count` counts calls once each; `error_count` counts errored
attempts. These counters accumulate while each relationship remains
in the index; they are not rolling 90-day counts. Inactive relationships expire 90 days after
their last observation. `team` appears only when the effective query covers one
team, including a multi-team token narrowed to one team.

The catalog's `is_entry_point` currently requires a `service` filter and is computed
across that service's environments. Without `service`, catalog rows report `false`; with an
environment filter, that flag can reflect another environment. Use function detail with the
required service/name and intended environment to verify entry-point observations in scope.

A never-observed `(service, name)` returns `200` from the detail route with
`observed_count: 0`, empty caller/callee lists and omitted `first_seen_at` / `last_seen_at`.
A null caller name means the function was observed as an entry point or without its parent.
Observed callers are evidence from recorded
execution, not a list of every possible dependency.

Examples return previews by default; `include=values` adds full stored values. The endpoint
returns at most five retained examples, without pagination. The store retains
examples per caller/callee edge and pools them for this response. Environment filtering and
expired source traces can reduce the result, including to an empty list. These examples are
not a full execution history.

Each function example identifies `trace_id`, `path`, `attempt`, `started_at` and `status`,
with `input` and `output` capture metadata when those slots were reported. An unreported slot
is omitted, rather than returned with an empty state. `include=values` adds readable bytes
under `value` within those objects. A zero-length payload omits `value` and `bytes_count`
while retaining `encoding` and `truncated`. Unlike the trace-values route, retained examples
identify the attempt whose inputs and outputs are read. They do not provide arbitrary
trace/attempt selection.

## Discover tags and check recording health

| Route | Use |
| - | - |
| `GET /v1/tags` | Discover recorded tag keys; `team`, `environment`, `service`, `limit`, `cursor` |
| `GET /v1/coverage` | Read observation and loss information for the selected scope |
| `GET /v1/health` | Read server storage, reported loss and service activity for the selected scope |

All three require a read token and accept scope filters. `health` is not an unauthenticated
liveness endpoint. The relay's own `/healthz` and `/metrics` live on its health listener,
configured separately with `-health-addr`.

`GET /v1/tags` returns paginated `items` containing `key`, `services` and
`distinct_value_count`, sorted by key. It lists keys and counts rather than full tag values.

`GET /v1/coverage` is not paginated. Its `services` rows contain `service`, optional
`environment`, `traces_24h`, `marked_functions_seen`, `records_lost_24h`, `records_shed_24h`
and `last_seen_at`. The marked-function count describes observed functions, not uninstrumented
code. Activity/loss fields and the observed-function index have different lifetimes.

`GET /v1/health` returns `status`, `mode`, `shape_store`, `value_store`, `stubs_swept_24h` and
`services`. `shape_store` contains `disk_used_bytes` and `effective_retention_days`. `value_store`
contains `bytes_used`, `byte_budget` and `effective_retention_estimate_hours`. Service rows
report recorded loss, shedding and last activity. Healthy responses use HTTP `200`; degraded
responses use `503`. A storage estimate is not guaranteed value
availability for an individual trace.

## Errors

The rate-limited read surface reports `X-RateLimit-Limit`, `X-RateLimit-Remaining` and
`X-RateLimit-Reset`. On `429`, honor `Retry-After` before retrying; it is an integer number
of seconds capped at `60`. Bootstrap capabilities are excluded from per-token rate limiting.

| HTTP status / code | What to check |
| - | - |
| `401 unauthenticated` | Missing, invalid or revoked credential |
| `403 forbidden_role` | Read versus ingest token role |
| `400 conflicting_filters` | Mutually exclusive environment filters |
| `400 invalid_cursor` | Cursor received from the previous page |
| `422 service_required` | Required `service` on function detail/examples |
| `429 rate_limited` | Back off using `Retry-After`, integer seconds capped at `60` |

Errors use an `error` object containing `code` and `message`, with optional machine-readable
`details`. Invalid query syntax uses `400 invalid_request`; exceeding the by-ID search bound
uses `422 too_many_trace_ids`. Missing `name` on function detail/examples uses
`400 invalid_request`.

For `404` on a named trace, “not visible to this token” and “absent” have the same response.
Do not infer that the request never ran. For missing data, follow
[the recording path](https://docs.vexlo.ai/deployment/troubleshooting.md).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.