Skip to content

Trace Read API

The Trace read API exposes project-scoped trace, conversation, and observed-user evidence. It is separate from OTLP ingestion even though both use /v1/traces:

View as Markdown Open the plain-text version of this page.
text
POST /v1/traces  -> ingest OTLP
GET  /v1/traces  -> query trace summaries

Use the OTLP/HTTP API for writes and this page for reads.

Authentication#

Public read routes require a project API key:

http
Authorization: Bearer <project API key>

The key needs telemetry:read. The API key determines the organization and project. Public callers cannot select another project with a query parameter.

bash
export PROVON_API_URL="https://api.provon.dev/v1"
export PROVON_API_KEY="your_project_api_key"

For local development, set PROVON_API_URL to http://127.0.0.1:3000/v1.

List And Search Traces#

http
GET /v1/traces

Query parameters:

Parameter Meaning
limit Page size from 1 through 500, default 100
cursor Opaque pagination.nextCursor from the previous response
query Search value
searchType Comma-separated search fields
level Comma-separated ok, error, or unknown
issue errors to restrict to error traces, or guardrails to restrict to guardrail-blocked traces
filter Opaque encoded filter state produced by the Workbench
range Relative range or <startMs>-<endMs>, default 24 hours

The same issue and filter parameters apply to GET /v1/traces/stats.

Search types:

text
trace-id
span-id
user-id
conversation-id
span-name
operation-name
content
input
output

Example:

bash
curl --get "$PROVON_API_URL/traces" \
  -H "Authorization: Bearer $PROVON_API_KEY" \
  --data-urlencode "query=permission denied" \
  --data-urlencode "searchType=span-name,content" \
  --data-urlencode "level=error" \
  --data-urlencode "range=24h" \
  --data-urlencode "limit=20"

Response:

json
{
  "traces": [],
  "pagination": {
    "limit": 20,
    "nextCursor": null
  }
}

Pass nextCursor unchanged in the next request. Do not parse or construct cursors.

Trace summaries include root operation, timing, status, span and error counts, user and conversation identity, environment, type, model, provider, agent, workflow, usage, cost, and ingest timestamps when those values are available.

input_preview holds the trace's last user message and output_preview its last assistant message that carries text. Both anchor to the newest qualifying message so they describe the same turn. Tool results, tool calls, and injected context are excluded; a non-conforming payload falls back to its longest readable string. Either is null when content is absent or withheld by retention.

Trace Statistics#

http
GET /v1/traces/stats

The endpoint accepts query, searchType, level, and range. It returns time buckets containing trace and error-trace counts. The server chooses a bucket width appropriate for the requested range.

bash
curl --get "$PROVON_API_URL/traces/stats" \
  -H "Authorization: Bearer $PROVON_API_KEY" \
  --data-urlencode "range=24h" \
  --data-urlencode "level=error"

Guardrail Stats#

http
GET /v1/traces/guardrail-stats

Aggregate guardrail-hit counts for a set of guardrail plugin IDs. The required pluginId query parameter is a comma-separated list of 1 to 100 valid plugin IDs; it also accepts range. A malformed or out-of-range pluginId returns 400.

Trace Detail Subject#

http
GET /v1/traces/:traceId/detail

Resolves the fused trace/conversation detail subject for the Workbench: an anchor span, a bounded trajectory outline, and trajectory pagination. It accepts anchorSpanId and trajectoryLimit (page size of 50). A missing anchor trace returns 404; an anchor trace not present in the conversation returns 409.

Trace Overview#

http
GET /v1/traces/:traceId

Use the overview for bounded trace metadata and paginated span summaries:

Parameter Meaning
limit Span summaries, default 100 and runtime maximum 500
cursor nextSpanCursor from the previous overview response

Response shape:

json
{
  "summary": {},
  "spanSummaries": [],
  "spanLimit": 100,
  "nextSpanCursor": null,
  "hasMoreSpans": false,
  "totalSpanCount": 0
}

The default maximum serialized overview response is 1,000,000 bytes. Use a smaller limit when the server returns 413.

Complete Spans#

List all normalized spans for a trace:

http
GET /v1/traces/:traceId/spans

Fetch one span:

http
GET /v1/traces/:traceId/spans/:spanId

The single-span route returns 404 when the span does not exist in the authenticated project.

Normalized spans contain core OTel fields, attributes, resource attributes, events, observed-user projection, and GenAI projection. See Tracing attribute reference.

Trace Attachments#

Retained span values can contain validated attachment references for large supported content. Fetch an attachment with:

http
GET /v1/traces/:traceId/spans/:spanId/attachments/:contentHash

The server verifies that:

  • the referenced span belongs to the authenticated project;
  • the span contains the requested content hash;
  • the blob key belongs to that project and the trace-attachment namespace.

Images and PDFs retain their safe content type. Other content is returned as application/octet-stream. Missing blob storage returns 503; missing or invalid references return 404.

Conversations#

List conversation summaries:

http
GET /v1/conversations

Query parameters:

Parameter Meaning
limit Page size from 1 through 500, default 100
cursor Opaque next cursor
range Relative or explicit range, default 24 hours
search Conversation search value
userId Exact observed-user ID
filter Opaque encoded filter state produced by the Workbench

List traces in one conversation:

http
GET /v1/conversations/:conversationId/traces

This route accepts limit (fixed page size of 50) and cursor. It also accepts anchorTraceId, which anchors the page around one trace; cursor and anchorTraceId are mutually exclusive. The response pagination includes nextCursor, prevCursor, anchorIndex, and totalTraceCount in addition to limit.

Read the fused conversation outline (turns, trace groups, and bounded span summaries) and the whole-conversation span forest:

http
GET /v1/conversations/:conversationId/trajectory
GET /v1/conversations/:conversationId/spans

The trajectory route accepts limit (page size of 50), cursor, anchorTraceId, and anchorSpanId. The span-forest route accepts traceLimit (1 through 200, default 50). Both are size-bounded and return 413 when the serialized response exceeds the overview limit.

Resolve deferred trajectory step content (full step messages and tool payloads) in one batch:

http
POST /v1/trajectory/content

The body is { "refs": [{ "currentSpan": { "traceId", "spanId" }, "previousSpan": <null|same> }] }; at most 64 refs per request (MAX_TRAJECTORY_CONTENT_REFS); more returns 400. The response is { "contents": [...] }.

Observed Users#

http
GET /v1/observed-users

The route accepts limit, cursor, range, search, and filter. Results aggregate trace, conversation, span, error, environment, model, token, and cost dimensions by observed user.id.

Read one observed user:

http
GET /v1/observed-users/:userId

Returns 404 when no observed user matches.

Observed users are application users found in telemetry, not Provon workspace members.

Time Ranges#

Relative ranges use minutes, hours, or days:

text
30m
6h
24h
7d

Explicit ranges use epoch milliseconds:

text
<startMs>-<endMs>

Trace, conversation, user, log, metric, and statistics list routes are time bounded. When range is omitted, the read API uses the last 24 hours. GET /v1/conversations/:conversationId/traces is cursor bounded instead; it returns traces for one already-selected conversation.

Read Consistency#

OTLP acceptance and trace reads are asynchronous:

  1. POST /v1/traces stages the payload and queues ingest.
  2. Background ingest normalizes and stores spans.
  3. Summary maintenance materializes trace read models.
  4. GET /v1/traces and higher-level views become current.

A successful ingest jobId is not a read cursor and does not prove summary visibility. Poll for the known trace ID with bounded backoff when an integration requires read-after-ingest verification.