Skip to content

Dashboards API

Project dashboards let you build persistent, shareable views over normalized telemetry. Each dashboard is a collection of widgets that query the spans or findings view. Queries are executed by the telemetry backend and streamed to the Workbench as Server-Sent Events.

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

When To Use It#

Use the Dashboards API when you want to:

  • create or update dashboards programmatically;
  • embed dashboard definitions in project configuration;
  • run ad-hoc widget queries outside the Workbench.

For interactive exploration, use the Workbench Dashboards view.

Authentication#

All routes are project-qualified under /v1/projects/:projectId.

Action API key capability Workbench permission
List, overview, get a dashboard workspace:read project:read
Create, update, delete, set default workspace:write project:update
Execute widget queries (POST .../dashboard-queries) telemetry:read project:data:read

Dashboard Definition#

A dashboard body is { "widgets": WidgetDefinition[] }. Each widget follows this shape:

json
{
  "id": "requests",
  "title": "Gateway requests",
  "layout": { "columnSpan": 6, "rowSpan": 2 },
  "query": {
    "view": "spans",
    "shape": "timeseries",
    "metric": "trace.count",
    "dimensions": ["gen_ai.operation.name"],
    "timeBucket": "hour",
    "filters": [],
    "limit": 100
  },
  "visual": { "kind": "line", "seriesLayout": "overlap" }
}
  • query.view is one of spans or findings.
  • query.shape is one of single, timeseries, or breakdown.
  • visual.kind is one of metric, line, area, bar, horizontal_bar, donut, radial, table, summary, or list.
  • layout.columnSpan is one of 2, 3, 4, 5, 6, 8, 12; layout.rowSpan is one of 1, 2, 3.

A dashboard may contain at most 24 widgets (maxDashboardWidgets). Time range is not a per-widget field; it is supplied per request (see below).

List Dashboards#

bash
curl "$PROVON_API_URL/projects/$PROJECT_ID/dashboards" \
  -H "Authorization: Bearer $PROVON_API_KEY"

Dashboard Overview#

bash
curl "$PROVON_API_URL/projects/$PROJECT_ID/dashboard-overview" \
  -H "Authorization: Bearer $PROVON_API_KEY"

Returns the project's dashboard list together with the default dashboard. Pass an optional ?dashboardId=<id> query parameter to narrow the overview to one dashboard.

Create A Dashboard#

bash
curl -X POST "$PROVON_API_URL/projects/$PROJECT_ID/dashboards" \
  -H "Authorization: Bearer $PROVON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Gateway health",
    "description": "Request volume, errors, and latency",
    "widgets": [
      {
        "id": "requests",
        "title": "Gateway requests",
        "layout": { "columnSpan": 6, "rowSpan": 2 },
        "query": { "view": "spans", "shape": "timeseries", "metric": "trace.count" },
        "visual": { "kind": "line" }
      }
    ]
  }'

Validation failures return 400 INVALID_DASHBOARD (or INVALID_DASHBOARD_DEFINITION on the streaming route).

Get, Update, And Delete#

bash
# Get
curl "$PROVON_API_URL/projects/$PROJECT_ID/dashboards/$DASHBOARD_ID" \
  -H "Authorization: Bearer $PROVON_API_KEY"

# Update
curl -X PATCH "$PROVON_API_URL/projects/$PROJECT_ID/dashboards/$DASHBOARD_ID" \
  -H "Authorization: Bearer $PROVON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Updated name", "widgets": [ ... ]}'

# Delete
curl -X DELETE "$PROVON_API_URL/projects/$PROJECT_ID/dashboards/$DASHBOARD_ID" \
  -H "Authorization: Bearer $PROVON_API_KEY"

A missing dashboard returns 404 DASHBOARD_NOT_FOUND.

Set The Default Dashboard#

bash
curl -X PUT "$PROVON_API_URL/projects/$PROJECT_ID/default-dashboard" \
  -H "Authorization: Bearer $PROVON_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"dashboardId": "<dashboard-id>"}'

dashboardId must be a non-empty string (400 INVALID_DASHBOARD_ID otherwise). The default dashboard is shown first when a project opens the Dashboards view. The response is the updated dashboard list.

Execute A Widget Query#

Run a set of widget queries and stream results. The body is { "range": "<time-range>", "widgets": WidgetDefinition[] }; range uses the same relative, preset, or <startMs>-<endMs> forms documented in Trace Read API.

bash
curl -X POST "$PROVON_API_URL/projects/$PROJECT_ID/dashboard-queries" \
  -H "Authorization: Bearer $PROVON_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "range": "24h",
    "widgets": [
      {
        "id": "requests",
        "title": "Gateway requests",
        "layout": { "columnSpan": 6, "rowSpan": 2 },
        "query": { "view": "spans", "shape": "timeseries", "metric": "trace.count" },
        "visual": { "kind": "line" }
      }
    ]
  }'

The response is a Server-Sent Events stream (text/event-stream, Cache-Control: no-cache, Connection: keep-alive). At most 24 widgets can be requested; the query service executes them with bounded concurrency (default maxConcurrency = 3 when the service does not declare its own capacity). More than 24 widgets returns 400 DASHBOARD_WIDGET_LIMIT_EXCEEDED.

Stream Events#

Event Data fields
init totalWidgets, maxConcurrency
progress completedWidgets, totalWidgets, index, widgetId, percent, durationMs
widget_data widgetId, status (success or error), rows (or [] on error), optional trend (success only), error (error only), durationMs
complete success, durationMs, completedWidgets
error message

Example stream:

text
event: init
data: {"totalWidgets":2,"maxConcurrency":3}

event: progress
data: {"completedWidgets":1,"totalWidgets":2,"index":0,"widgetId":"requests","percent":50,"durationMs":120}

event: widget_data
data: {"widgetId":"requests","status":"success","rows":[...],"trend":null,"durationMs":120}

event: progress
data: {"completedWidgets":2,"totalWidgets":2,"index":1,"widgetId":"errors","percent":100,"durationMs":165}

event: widget_data
data: {"widgetId":"errors","status":"error","error":"...","rows":[],"durationMs":45}

event: complete
data: {"success":true,"durationMs":165,"completedWidgets":2}

The client should read events until the stream closes and handle error events as failures. Cancelling the HTTP request aborts in-flight widget queries.

Limitations#

  • Dashboard definitions are project-scoped; sharing across projects requires copying the definition.
  • Widget query syntax is validated by the telemetry backend and may differ slightly between DuckDB and Cloudflare R2 SQL deployments.
  • The API does not render charts; it returns the query result rows and trend that the Workbench visualizes.