Skip to content

Telemetry Read API

The Telemetry Read API returns normalized OpenTelemetry logs and metric points for a project. Use the Trace Read API for trace, span, conversation, and observed-user views. Use the

View as Markdown Open the plain-text version of this page.

Base URL:

text
https://api.provon.dev/v1

Public service clients use a project API key with telemetry:read:

http
Authorization: Bearer <PROVON_API_KEY>

The key selects the project, so public routes do not require a project ID in the path.

Endpoints#

Method Public API path Workbench path Purpose
GET /logs /projects/:projectId/logs List logs
GET /metrics /projects/:projectId/metrics List metrics

The project-qualified forms are for signed-in Workbench calls and project-scoped clients that need an explicit path. API integrations should normally use /logs and /metrics.

Time Range#

Every request must provide one time-range form:

Form Example
Relative range range=15m, range=6h, or range=7d
Absolute range startMs=1760000000000&endMs=1760086400000
Encoded custom range range=1760000000000-1760086400000

Times are Unix milliseconds. When using startMs/endMs, both values are required and startMs must not exceed endMs.

List Logs#

http
GET /v1/logs?range=1h&limit=100
Authorization: Bearer <PROVON_API_KEY>

Query parameters:

Parameter Type Purpose
range string Relative or encoded absolute range
startMs Unix millisecond Absolute range start
endMs Unix millisecond Absolute range end
traceId string Return logs correlated to one trace
eventName string Return logs with one normalized event name
limit integer Page size from 1 to 500; default 100
cursor string Opaque cursor from the previous response

Response:

json
{
  "logs": [
    {
      "trace_id": "4f3c2f...",
      "span_id": "9a41...",
      "time_ms": 1760086000000,
      "observed_time_ms": 1760086000042,
      "severity_text": "INFO",
      "body": {
        "message": "tool call completed"
      },
      "attributes": {
        "tool.name": "lookup_order"
      },
      "resource_attributes": {
        "service.name": "support-agent"
      },
      "scope_name": "agent-runtime",
      "event_name": "tool.result"
    }
  ],
  "pagination": {
    "limit": 100,
    "nextCursor": null
  }
}

body and attribute values are JSON values. trace_id, span_id, timestamps, severity, scope, and event name can be null when the source did not provide them.

List Metrics#

http
GET /v1/metrics?range=24h&metricNames=gen_ai.client.token.usage,gen_ai.client.operation.duration
Authorization: Bearer <PROVON_API_KEY>

Query parameters:

Parameter Type Purpose
range string Relative or encoded absolute range
startMs Unix millisecond Absolute range start
endMs Unix millisecond Absolute range end
metricNames CSV string Exact metric names to include
limit integer Page size from 1 to 500; default 100
cursor string Opaque cursor from the previous response

Response:

json
{
  "metrics": [
    {
      "metric_name": "gen_ai.client.operation.duration",
      "description": "Model operation duration",
      "unit": "s",
      "type": "histogram",
      "start_time_ms": 1760085000000,
      "time_ms": 1760086000000,
      "attributes": {
        "gen_ai.operation.name": "chat",
        "gen_ai.provider.name": "openai"
      },
      "resource_attributes": {
        "service.name": "support-agent"
      },
      "scope_name": "agent-runtime",
      "value": null,
      "count": 24,
      "sum": 31.2,
      "min": 0.4,
      "max": 4.8,
      "bucket_counts": [3, 12, 8, 1],
      "explicit_bounds": [0.5, 1, 2],
      "exemplars": null
    }
  ],
  "pagination": {
    "limit": 100,
    "nextCursor": null
  }
}

Metric type is one of gauge, sum, histogram, exponential_histogram, or summary. Fields that do not apply to that type are null.

Pagination#

Results use cursor pagination in descending telemetry time order. Pass pagination.nextCursor unchanged:

bash
curl --get "$PROVON_API_URL/logs" \
  -H "Authorization: Bearer $PROVON_API_KEY" \
  --data-urlencode "range=24h" \
  --data-urlencode "cursor=$NEXT_CURSOR"

Treat the cursor as opaque. Its encoding can change independently of record fields.

Read Consistency#

OTLP ingestion is asynchronous. A successful POST /v1/logs or POST /v1/metrics on the OTLP surface means the payload was accepted for processing; it may not be immediately visible through this API.

For verification:

  1. keep the original signal timestamp inside the requested range;
  2. poll with bounded backoff;
  3. narrow by traceId, eventName, or metricNames where possible;
  4. stop retrying on authentication or validation errors.

Errors#

Status Meaning
400 Missing/invalid time range or malformed cursor
401 Missing or invalid project API key
403 API key does not include telemetry:read
500 Query or storage failure

Authentication failures use the shared structured API error. Some query-validation failures return a compact { "error": "..." } body; clients should use the HTTP status as the primary control signal.