# 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`:

```text
POST /v1/traces  -> ingest OTLP
GET  /v1/traces  -> query trace summaries
```

Use the [OTLP/HTTP API](./otlp-api.md) 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_BASE_URL="http://127.0.0.1:3000"
export PROVON_API_KEY="your_project_api_key"
```

## 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`               |
| `range`      | Relative range or `<startMs>-<endMs>`, default 24 hours   |

Search types:

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

Example:

```bash
curl --get "$PROVON_BASE_URL/v1/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, input/output previews,
and ingest timestamps when those values are available.

## 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_BASE_URL/v1/traces/stats" \
  -H "Authorization: Bearer $PROVON_API_KEY" \
  --data-urlencode "range=24h" \
  --data-urlencode "level=error"
```

## Trace Overview

```http
GET /v1/traces/:traceId/overview
```

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](./tracing-attributes.md).

## 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                       |

List traces in one conversation:

```http
GET /v1/conversations/:conversationId/traces
```

This route accepts `limit` and `cursor`.

## Observed Users

```http
GET /v1/users
```

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

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>
```

All list and statistics requests are time bounded. When `range` is omitted, the read API uses the
last 24 hours.

## 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.

## Related Docs

- [Tracing quickstart](./tracing-quickstart.md)
- [Explore traces](./trace-explorer.md)
- [Tracing CLI](./tracing-cli.md)
- [OTLP/HTTP API](./otlp-api.md)
- [Telemetry architecture](./telemetry.md)
- [Tracing troubleshooting](./troubleshooting.md)
