Telemetry API
Telemetry of a workspace's pipelines: pipeline runs and their traces, the results job runs declare, and per-pipeline and per-dataset statistics.
Base URL and authentication
Each workspace keeps its data on the data plane of its region. Its services are not on
api.dlthub.com and do not accept API keys. To call them:
- Read
dataplane_urlfromGET https://api.dlthub.com/api/v1/workspaces/{workspace_id}. This is the base URL of every data plane service: Dataplane, Logs and Telemetry API. - Exchange your API key for a data plane token with
POST https://api.dlthub.com/api/v1/workspaces/{workspace_id}/-issue-dataplane-token. The token is valid for one workspace untilexpires_at, currently 10 minutes after it was issued; request a new one before then. - Call the service at
dataplane_urlwithAuthorization: Bearer <token>.
Every workspace member can read logs, telemetry and file lists. Only workspace owners can read
or change variables, so workspace API keys, which are DEVELOPER or VIEWER, cannot. Uploads use
a separate token: POST .../deployments/-issue-upload (or /configurations/-issue-upload)
returns an upload_token and the upload_url to send the files to, both valid for one upload
and 10 minutes.
The data planes today:
| Region | dataplane_url |
|---|---|
Europe (eu1, europe-west4) | https://eu1.dlthub.com |
US East (us1, us-east4) | https://us1.dlthub.com |
Versioning
The API version is part of the path. Endpoints under /v1 are stable: breaking changes ship
only under a new version prefix. New endpoints, optional parameters and response fields can
be added to /v1 at any time, so ignore fields and enum values you do not know.
Endpoints
List dataset overview
GET /telemetry/v1/workspaces/{workspace_id}/datasets/-/stats
One row per dataset, aggregated over the pipeline runs whose started_at falls in the
time range [start, end). Most recently run first by default.
Datasets are grouped by name across destinations. Runs without a dataset, for example ones that failed before loading, are not counted.
Search with q over the dataset name, filter on what a row displays, and sort
with paired sort and order lists.
Request
- Parameters
- curl
- Python
Path parameters
| Name | Type | Description |
|---|---|---|
workspace_id | string (uuid) | ID of the workspace |
Query parameters
| Name | Type | Description |
|---|---|---|
start | string (date-time) or null | Lower bound (inclusive) on started_at, as a naive local time read in timezone, e.g. 2026-03-01T00:00:00. Defaults to 7 days before end. |
end | string (date-time) or null | Upper bound (exclusive) on started_at, as a naive local time read in timezone, e.g. 2026-03-11T00:00:00. Defaults to now. |
timezone | string | IANA timezone in which start and end are read, e.g. Europe/Berlin. Default UTC. |
q | string or null | Case-insensitive substring match on dataset_name. |
dataset_name | array of string or null | Exact match on dataset_name. Repeat the parameter to match any of several values. |
latest_status | array of string or null | Exact match on latest_status. Repeat the parameter to match any of several values. One of: succeeded, failed. |
latest_destination_name | array of string or null | Exact match on latest_destination_name. Repeat the parameter to match any of several values. |
sort | array of string or null | Keys to sort by, applied in the order given. Pairs positionally with order, which must have the same number of entries. One of: latest_pipeline_run_at, total_pipeline_run_count, success_ratio, average_duration_ms, total_rows_loaded, dataset_name. |
Pagination: limit, offset, order, cursor, see Lists and pagination
curl "$DATAPLANE_URL/telemetry/v1/workspaces/$WORKSPACE_ID/datasets/-/stats" \
-H "Authorization: Bearer $DATAPLANE_TOKEN"
import os
import requests
response = requests.get(
"<dataplane_url>/telemetry/v1/workspaces/<workspace_id>/datasets/-/stats",
headers={"Authorization": f"Bearer {os.environ['DATAPLANE_TOKEN']}"},
)
response.raise_for_status()
print(response.json())
Response (200, 4xx, 5xx)
- Example
- Fields
- Errors
{
"items": [
{
"average_duration_ms": 0,
"dataset_name": "<dataset_name>",
"distinct_pipeline_count": 0,
"latest_destination_name": "<latest_destination_name>",
"latest_pipeline_name": "<latest_pipeline_name>",
"latest_pipeline_run_at": "2026-01-01T00:00:00Z",
"latest_pipeline_run_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"latest_status": "succeeded",
"schema_migration_count": 0,
"succeeded_pipeline_run_count": 0,
"success_ratio": 0,
"table_count": 0,
"total_bytes_loaded": 0,
"total_pipeline_run_count": 0,
"total_rows_loaded": 0
}
],
"limit": 0,
"next_cursor": "<next_cursor>",
"offset": 0,
"total": 0
}
| Field | Type | Description |
|---|---|---|
items | array of object | The rows of this page, in sort order. |
items[].average_duration_ms | integer or null | Mean duration_ms in the range, rounded; null when no run has a duration. |
items[].dataset_name | string | Name of the dataset, across destinations. |
items[].distinct_pipeline_count | integer | Number of distinct pipelines that ran into this dataset in the range. |
items[].latest_destination_name | string or null | Destination of the most recent pipeline run in the time range. |
items[].latest_pipeline_name | string or null | Pipeline of the most recent pipeline run in the time range. |
items[].latest_pipeline_run_at | string (date-time) or null | When the most recent pipeline run in the time range started. |
items[].latest_pipeline_run_id | string (uuid) or null | ID of the most recent pipeline run in the time range. |
items[].latest_status | string or null | Status of the most recent pipeline run in the time range. One of: succeeded, failed. |
items[].schema_migration_count | integer | Runs in the range with has_schema_migration. |
items[].succeeded_pipeline_run_count | integer | Pipeline runs in the range with status succeeded. |
items[].success_ratio | number | Succeeded ÷ total, from 0 to 1. |
items[].table_count | integer | Distinct user tables ever seen in a dataset of this name (all time, _dlt_* excluded). Default: 0. |
items[].total_bytes_loaded | integer | Sum of normalized bytes (size of the normalized files) over succeeded runs in the time range. |
items[].total_pipeline_run_count | integer | Pipeline runs in the range. |
items[].total_rows_loaded | integer | Sum of normalized rows over succeeded runs in the time range. |
limit | integer | The page size this page was fetched with. |
next_cursor | string or null | Cursor for the page after this one; null on the last. |
offset | integer | How many rows were skipped before this page. |
total | integer | Rows matching the filters, reported up to 10001. |
400Bad Request401Unauthorized403Forbidden500Internal Server Error
Each error returns the error body.
Get job result
GET /telemetry/v1/workspaces/{workspace_id}/job-runs/{job_run_id}/result
The result a job run declared: for an agent, its status, summary, token usage and cost;
for other jobs, the declared result. A run has at most one.
job_run_id is the job run's id from the runtime API, not a pipeline_run_id. Answers 404
when the run declared no result. For the agent's per-turn tool calls and everything else the
job delivered, read /result-trace.
Request
- Parameters
- curl
- Python
Path parameters
| Name | Type | Description |
|---|---|---|
workspace_id | string (uuid) | ID of the workspace |
job_run_id | string (uuid) | ID of the job run |
curl "$DATAPLANE_URL/telemetry/v1/workspaces/$WORKSPACE_ID/job-runs/$JOB_RUN_ID/result" \
-H "Authorization: Bearer $DATAPLANE_TOKEN"
import os
import requests
response = requests.get(
"<dataplane_url>/telemetry/v1/workspaces/<workspace_id>/job-runs/<job_run_id>/result",
headers={"Authorization": f"Bearer {os.environ['DATAPLANE_TOKEN']}"},
)
response.raise_for_status()
print(response.json())
Response (200, 4xx, 5xx)
- Example
- Fields
- Errors
{
"agent_status": "<agent_status>",
"cost_usd": "<cost_usd>",
"created_at": "2026-01-01T00:00:00Z",
"engine_version": 0,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"input_tokens": 0,
"job_ref": "<job_ref>",
"job_run_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"loop_type": "<loop_type>",
"model": "<model>",
"output_tokens": 0,
"result": "<result>",
"result_type": "<result_type>",
"stop_reason": "<stop_reason>",
"summary": "<summary>",
"total_tokens": 0,
"turn_count": 0,
"updated_at": "2026-01-01T00:00:00Z"
}
| Field | Type | Description |
|---|---|---|
agent_status | string or null | The agent's self-report, which may legitimately disagree with the run's own status: a failed agent inside a succeeded run is normal. |
cost_usd | string or null | Cost in USD the agent reported, as a decimal string. null when the result carries no agent trace, as for non-agent jobs. |
created_at | string (date-time) | When the result was first stored, UTC. |
engine_version | integer | Result format version; 1 when not declared. |
id | string (uuid) | Id of the job result. |
input_tokens | integer or null | Input tokens the agent used. null when the result carries no agent trace, as for non-agent jobs. |
job_ref | string | The job that declared the result. |
job_run_id | string (uuid) | Job run that declared the result. |
loop_type | string or null | Agent loop that ran. null when the result carries no agent trace, as for non-agent jobs. |
model | string or null | Model the agent ran with. null when the result carries no agent trace, as for non-agent jobs. |
output_tokens | integer or null | Output tokens the agent used. null when the result carries no agent trace, as for non-agent jobs. |
result | any | The job's declared output. Shape is job-defined. |
result_type | string | job.{category}.{name}, for example job.background_agent.{name}. |
stop_reason | string or null | Why the agent stopped. null when the result carries no agent trace, as for non-agent jobs. |
summary | string or null | Model-authored markdown, unbounded. Untrusted — render as user content. |
total_tokens | integer or null | Total tokens the agent used. null when the result carries no agent trace, as for non-agent jobs. |
turn_count | integer or null | Number of turns the agent took. null when the result carries no agent trace, as for non-agent jobs. |
updated_at | string (date-time) | When the result was last stored, UTC. |
400Bad Request401Unauthorized403Forbidden404Not Found500Internal Server Error
Each error returns the error body.
Get job result trace
GET /telemetry/v1/workspaces/{workspace_id}/job-runs/{job_run_id}/result-trace
The full result exactly as the job delivered it, including the agent's per-turn tool calls.
Fields beyond type and job_ref are passed through unchanged. job_run_id is the job run's
id from the runtime API, not a pipeline_run_id. Answers 404 when the run declared no result.
Results over 8 MiB answer 413 job_result_trace_too_large; the summary fields stay
available at /result.
Request
- Parameters
- curl
- Python
Path parameters
| Name | Type | Description |
|---|---|---|
workspace_id | string (uuid) | ID of the workspace |
job_run_id | string (uuid) | ID of the job run |
curl "$DATAPLANE_URL/telemetry/v1/workspaces/$WORKSPACE_ID/job-runs/$JOB_RUN_ID/result-trace" \
-H "Authorization: Bearer $DATAPLANE_TOKEN"
import os
import requests
response = requests.get(
"<dataplane_url>/telemetry/v1/workspaces/<workspace_id>/job-runs/<job_run_id>/result-trace",
headers={"Authorization": f"Bearer {os.environ['DATAPLANE_TOKEN']}"},
)
response.raise_for_status()
print(response.json())
Response (200, 4xx, 5xx)
- Example
- Fields
- Errors
{
"job_ref": "<job_ref>",
"type": "<type>"
}
| Field | Type | Description |
|---|---|---|
job_ref | string | The job that declared the result. |
type | string | The result type, job.{category}.{name}; job.background_agent.{name} for an agent. |
400Bad Request401Unauthorized403Forbidden404Not Found413Request Entity Too Large500Internal Server Error
Each error returns the error body.
List pipeline runs
GET /telemetry/v1/workspaces/{workspace_id}/pipeline-runs
Lists the pipeline runs of a workspace whose started_at falls in the time range
[start, end), newest first by default.
Search with q over the pipeline name; filter by status, pipeline, dataset,
destination, job run, or empty run; sort with paired sort and order lists.
Request
- Parameters
- curl
- Python
Path parameters
| Name | Type | Description |
|---|---|---|
workspace_id | string (uuid) | ID of the workspace |
Query parameters
| Name | Type | Description |
|---|---|---|
start | string (date-time) or null | Lower bound (inclusive) on started_at, as a naive local time read in timezone, e.g. 2026-03-01T00:00:00. Defaults to 7 days before end. |
end | string (date-time) or null | Upper bound (exclusive) on started_at, as a naive local time read in timezone, e.g. 2026-03-11T00:00:00. Defaults to now. |
timezone | string | IANA timezone in which start and end are read, e.g. Europe/Berlin. Default UTC. |
q | string or null | Case-insensitive substring match on pipeline_name. |
status | array of string or null | Exact match on status. Repeat the parameter to match any of several values. One of: succeeded, failed. |
pipeline_name | array of string or null | Exact match on pipeline_name. Repeat the parameter to match any of several values. |
dataset_name | array of string or null | Exact match on dataset_name. Repeat the parameter to match any of several values. |
destination_name | array of string or null | Exact match on destination_name. Repeat the parameter to match any of several values. |
job_run_id | array of string (uuid) or null | Exact match on job_run_id. Repeat the parameter to match any of several values. |
is_empty_run | boolean or null | Match is_empty_run. Omit to list both. |
sort | array of string or null | Keys to sort by, applied in the order given. Pairs positionally with order, which must have the same number of entries. One of: started_at, duration_ms, total_rows_loaded, total_bytes_loaded, finished_at. |
Pagination: limit, offset, order, cursor, see Lists and pagination
curl "$DATAPLANE_URL/telemetry/v1/workspaces/$WORKSPACE_ID/pipeline-runs" \
-H "Authorization: Bearer $DATAPLANE_TOKEN"
import os
import requests
response = requests.get(
"<dataplane_url>/telemetry/v1/workspaces/<workspace_id>/pipeline-runs",
headers={"Authorization": f"Bearer {os.environ['DATAPLANE_TOKEN']}"},
)
response.raise_for_status()
print(response.json())
Response (200, 4xx, 5xx)
- Example
- Fields
- Errors
{
"items": [
{
"created_at": "2026-01-01T00:00:00Z",
"dataset_name": "<dataset_name>",
"destination_name": "<destination_name>",
"dlt_version": "<dlt_version>",
"duration_ms": 0,
"error_message": "<error_message>",
"error_step": "<error_step>",
"finished_at": "2026-01-01T00:00:00Z",
"has_schema_migration": false,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"pipeline_name": "<pipeline_name>",
"started_at": "2026-01-01T00:00:00Z",
"status": "succeeded",
"total_bytes_loaded": 0,
"total_rows_extracted": 0,
"total_rows_loaded": 0,
"updated_at": "2026-01-01T00:00:00Z"
}
],
"limit": 0,
"next_cursor": "<next_cursor>",
"offset": 0,
"total": 0
}
| Field | Type | Description |
|---|---|---|
items | array of object | The rows of this page, in sort order. |
items[].created_at | string (date-time) | When this run was first stored from telemetry, UTC. |
items[].dataset_name | string or null | Dataset the run loaded into, from its load step; null when the run did not reach load. |
items[].destination_name | string or null | Destination the run loaded to, from its load step; null when the run did not reach load. |
items[].dlt_version | string or null | dlt version that ran the pipeline, from the trace's execution context. |
items[].duration_ms | integer or null | finished_at − started_at in milliseconds. |
items[].error_message | string or null | Exception message of that step. |
items[].error_step | string or null | First step that raised, for example extract, normalize or load. |
items[].finished_at | string (date-time) or null | End of the run from the dlt trace, UTC. |
items[].has_schema_migration | boolean or null | True when the load step created or changed user tables (_dlt_* tables are ignored). |
items[].id | string (uuid) | ID of the pipeline run; not a job run ID. |
items[].pipeline_name | string | Name of the dlt pipeline. |
items[].started_at | string (date-time) or null | Start of the run from the dlt trace, UTC. |
items[].status | string | failed when any step raised, otherwise succeeded. One of: succeeded, failed. |
items[].total_bytes_loaded | integer | Bytes that dlt prepared for loading in this run (size of the normalized files). dlt does not report per-row load counts, so this is set even when loading failed. Default: 0. |
items[].total_rows_extracted | integer | Rows written by the extract step. Default: 0. |
items[].total_rows_loaded | integer | Rows that dlt prepared for loading in this run (normalized rows). dlt does not report per-row load counts, so this is set even when loading failed. Default: 0. |
items[].updated_at | string (date-time) | When this run was last updated from telemetry, UTC. |
limit | integer | The page size this page was fetched with. |
next_cursor | string or null | Cursor for the page after this one; null on the last. |
offset | integer | How many rows were skipped before this page. |
total | integer | Rows matching the filters, reported up to 10001. |
400Bad Request401Unauthorized403Forbidden500Internal Server Error
Each error returns the error body.
Get pipeline run
GET /telemetry/v1/workspaces/{workspace_id}/pipeline-runs/{pipeline_run_id}
One pipeline run (one dlt pipeline.run()), looked up by its id, with its per-table and
per-resource metrics and its load packages. Answers 404 when it is not in the workspace.
Request
- Parameters
- curl
- Python
Path parameters
| Name | Type | Description |
|---|---|---|
workspace_id | string (uuid) | ID of the workspace |
pipeline_run_id | string (uuid) | ID of the pipeline run |
curl "$DATAPLANE_URL/telemetry/v1/workspaces/$WORKSPACE_ID/pipeline-runs/$PIPELINE_RUN_ID" \
-H "Authorization: Bearer $DATAPLANE_TOKEN"
import os
import requests
response = requests.get(
"<dataplane_url>/telemetry/v1/workspaces/<workspace_id>/pipeline-runs/<pipeline_run_id>",
headers={"Authorization": f"Bearer {os.environ['DATAPLANE_TOKEN']}"},
)
response.raise_for_status()
print(response.json())
Response (200, 4xx, 5xx)
- Example
- Fields
- Errors
{
"created_at": "2026-01-01T00:00:00Z",
"dataset_name": "<dataset_name>",
"destination_name": "<destination_name>",
"dlt_plus_version": "<dlt_plus_version>",
"dlt_version": "<dlt_version>",
"duration_ms": 0,
"error_message": "<error_message>",
"error_step": "<error_step>",
"error_traceback": "<error_traceback>",
"extract_duration_ms": 0,
"finished_at": "2026-01-01T00:00:00Z",
"has_failed_load_jobs": false,
"has_pending_packages": false,
"has_schema_migration": false,
"id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"is_empty_run": false,
"job_run_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"load_duration_ms": 0,
"load_package_count": 0,
"load_packages": [],
"normalize_duration_ms": 0,
"os_name": "<os_name>",
"os_version": "<os_version>",
"pipeline_name": "<pipeline_name>",
"python_version": "<python_version>",
"resources": [],
"started_at": "2026-01-01T00:00:00Z",
"status": "succeeded",
"tables": [],
"total_bytes_extracted": 0,
"total_bytes_loaded": 0,
"total_rows_extracted": 0,
"total_rows_loaded": 0,
"transaction_id": "<transaction_id>",
"updated_at": "2026-01-01T00:00:00Z"
}
| Field | Type | Description |
|---|---|---|
created_at | string (date-time) | When this run was first stored from telemetry, UTC. |
dataset_name | string or null | Dataset the run loaded into, from its load step; null when the run did not reach load. |
destination_name | string or null | Destination the run loaded to, from its load step; null when the run did not reach load. |
dlt_plus_version | string or null | Version of the dlthub package, from the trace's execution context; null when it was not installed. |
dlt_version | string or null | dlt version that ran the pipeline, from the trace's execution context. |
duration_ms | integer or null | finished_at − started_at in milliseconds. |
error_message | string or null | Exception message of that step. |
error_step | string or null | First step that raised, for example extract, normalize or load. |
error_traceback | string or null | Stack trace of the step that raised. |
extract_duration_ms | integer or null | Duration of the extract step in milliseconds; null when it did not run. |
finished_at | string (date-time) or null | End of the run from the dlt trace, UTC. |
has_failed_load_jobs | boolean or null | True when any load package has failed jobs. Default: false. |
has_pending_packages | boolean or null | True when any load package is in a state other than loaded. Default: false. |
has_schema_migration | boolean or null | True when the load step created or changed user tables (_dlt_* tables are ignored). |
id | string (uuid) | ID of the pipeline run; not a job run ID. |
is_empty_run | boolean or null | True when the run did not fail and extract produced no load packages. Default: false. |
job_run_id | string (uuid) or null | Job run that sent this run's telemetry. |
load_duration_ms | integer or null | Duration of the load step in milliseconds; null when it did not run. |
load_package_count | integer or null | Number of load packages reported by the last step the run reached. Default: 0. |
load_packages | array of object | Load packages of the run. Default: []. |
load_packages[].completed_at | string (date-time) or null | When dlt completed the package, UTC; null while not completed. |
load_packages[].completed_job_count | integer or null | Jobs that completed. Default: 0. |
load_packages[].failed_job_count | integer or null | Jobs that failed. Default: 0. |
load_packages[].has_failed_load_jobs | boolean or null | True when any load job of the package failed. Default: false. |
load_packages[].has_schema_migration | boolean or null | True when loading this package created or changed user tables (_dlt_* tables are ignored). Default: false. |
load_packages[].is_pending | boolean or null | True when the package is not fully loaded yet. Default: false. |
load_packages[].job_count | integer or null | Number of jobs in the package. Default: 0. |
load_packages[].load_id | string | dlt load id of the package. |
load_packages[].load_status | string or null | State dlt reported for the package; loaded means fully loaded. One of: new, extracted, normalized, loaded, aborted. |
load_packages[].schema_hash | string or null | Version hash of that schema. |
load_packages[].schema_name | string or null | dlt schema the package was created with. |
load_packages[].total_bytes_loaded | integer or null | Bytes that dlt prepared for loading in this package (size of the normalized files, or of the extracted files when normalize reported none). dlt does not report per-row load counts, so this is set even when loading failed. Default: 0. |
load_packages[].total_rows_loaded | integer or null | Rows that dlt prepared for loading in this package (normalized rows, or extracted rows when normalize reported none). dlt does not report per-row load counts, so this is set even when loading failed. Default: 0. |
normalize_duration_ms | integer or null | Duration of the normalize step in milliseconds; null when it did not run. |
os_name | string or null | Operating system that ran the pipeline, from the trace's execution context. |
os_version | string or null | Version of that operating system. |
pipeline_name | string | Name of the dlt pipeline. |
python_version | string or null | Python version that ran the pipeline, from the trace's execution context. |
resources | array of object | One entry per extracted resource and load package. Default: []. |
resources[].bytes_extracted | integer or null | Size of the intermediate files the extract step wrote for this resource. |
resources[].parent_resource_name | string or null | Resource this transformer reads from; null for a top-level resource. |
resources[].resource_name | string | Name of the dlt resource. |
resources[].rows_extracted | integer or null | Rows the extract step wrote for this resource. |
resources[].schema_name | string | dlt schema of the resource's load package; empty when not reported. Default: "". |
resources[].write_disposition | string or null | From the resource hints. One of: append, replace, merge. |
started_at | string (date-time) or null | Start of the run from the dlt trace, UTC. |
status | string | failed when any step raised, otherwise succeeded. One of: succeeded, failed. |
tables | array of object | One entry per table and load package. Default: []. |
tables[].bytes_extracted | integer or null | Size of the intermediate files the extract step wrote for this table; null when not extracted. |
tables[].bytes_loaded | integer or null | Bytes that dlt prepared for loading for this table (size of the normalized files). dlt does not report per-row load counts, so this is set even when loading failed. |
tables[].file_format | string or null | Format of the file dlt loaded, for example parquet. |
tables[].load_duration_ms | integer or null | Duration of the table's load job in milliseconds; null when the table was not loaded. |
tables[].load_job_state | string or null | completed or failed; null when the table was not loaded. One of: completed, failed. |
tables[].rows_extracted | integer or null | Rows the extract step wrote for this table; null when not extracted. |
tables[].rows_loaded | integer or null | Rows that dlt prepared for loading for this table (normalized rows). dlt does not report per-row load counts, so this is set even when loading failed. |
tables[].schema_name | string | dlt schema of the table's load package; empty when not reported. Default: "". |
tables[].table_name | string | Name of the table. |
tables[].write_disposition | string or null | From the resource hints; null when the extract step reported none. One of: append, replace, merge. |
total_bytes_extracted | integer | Size of the intermediate files written by the extract step. Default: 0. |
total_bytes_loaded | integer | Bytes that dlt prepared for loading in this run (size of the normalized files). dlt does not report per-row load counts, so this is set even when loading failed. Default: 0. |
total_rows_extracted | integer | Rows written by the extract step. Default: 0. |
total_rows_loaded | integer | Rows that dlt prepared for loading in this run (normalized rows). dlt does not report per-row load counts, so this is set even when loading failed. Default: 0. |
transaction_id | string | dlt trace transaction id; one pipeline run per transaction. |
updated_at | string (date-time) | When this run was last updated from telemetry, UTC. |
400Bad Request401Unauthorized403Forbidden404Not Found500Internal Server Error
Each error returns the error body.
Get pipeline run trace
GET /telemetry/v1/workspaces/{workspace_id}/pipeline-runs/{pipeline_run_id}/trace
Returns the dlt trace of this pipeline run as dlt produced it: its extract, normalize and load steps and the execution context. Answers 404 when the run or its trace is not found.
Request
- Parameters
- curl
- Python
Path parameters
| Name | Type | Description |
|---|---|---|
workspace_id | string (uuid) | ID of the workspace |
pipeline_run_id | string (uuid) | ID of the pipeline run |
curl "$DATAPLANE_URL/telemetry/v1/workspaces/$WORKSPACE_ID/pipeline-runs/$PIPELINE_RUN_ID/trace" \
-H "Authorization: Bearer $DATAPLANE_TOKEN"
import os
import requests
response = requests.get(
"<dataplane_url>/telemetry/v1/workspaces/<workspace_id>/pipeline-runs/<pipeline_run_id>/trace",
headers={"Authorization": f"Bearer {os.environ['DATAPLANE_TOKEN']}"},
)
response.raise_for_status()
print(response.json())
Response (200, 4xx, 5xx)
- Example
- Fields
- Errors
{
"execution_context": {},
"pipeline_name": "<pipeline_name>",
"steps": [],
"transaction_id": "<transaction_id>"
}
| Field | Type | Description |
|---|---|---|
execution_context | map of any | The dlt, Python and host versions the pipeline ran with. |
pipeline_name | string | The pipeline that ran. |
steps | array of map of any | The extract, normalize and load steps, in order. |
transaction_id | string | The dlt transaction the trace records. |
400Bad Request401Unauthorized403Forbidden404Not Found500Internal Server Error
Each error returns the error body.
List pipeline overview
GET /telemetry/v1/workspaces/{workspace_id}/pipelines/-/stats
One row per pipeline, aggregated over the pipeline runs whose started_at falls in the
time range [start, end). Most recently run first by default.
Search with q over the pipeline name, filter on what a row displays, and sort
with paired sort and order lists.
Request
- Parameters
- curl
- Python
Path parameters
| Name | Type | Description |
|---|---|---|
workspace_id | string (uuid) | ID of the workspace |
Query parameters
| Name | Type | Description |
|---|---|---|
start | string (date-time) or null | Lower bound (inclusive) on started_at, as a naive local time read in timezone, e.g. 2026-03-01T00:00:00. Defaults to 7 days before end. |
end | string (date-time) or null | Upper bound (exclusive) on started_at, as a naive local time read in timezone, e.g. 2026-03-11T00:00:00. Defaults to now. |
timezone | string | IANA timezone in which start and end are read, e.g. Europe/Berlin. Default UTC. |
q | string or null | Case-insensitive substring match on pipeline_name. |
pipeline_name | array of string or null | Exact match on pipeline_name. Repeat the parameter to match any of several values. |
latest_status | array of string or null | Exact match on latest_status. Repeat the parameter to match any of several values. One of: succeeded, failed. |
latest_destination_name | array of string or null | Exact match on latest_destination_name. Repeat the parameter to match any of several values. |
sort | array of string or null | Keys to sort by, applied in the order given. Pairs positionally with order, which must have the same number of entries. One of: latest_pipeline_run_at, total_pipeline_run_count, success_ratio, average_duration_ms, total_rows_loaded, pipeline_name. |
Pagination: limit, offset, order, cursor, see Lists and pagination
curl "$DATAPLANE_URL/telemetry/v1/workspaces/$WORKSPACE_ID/pipelines/-/stats" \
-H "Authorization: Bearer $DATAPLANE_TOKEN"
import os
import requests
response = requests.get(
"<dataplane_url>/telemetry/v1/workspaces/<workspace_id>/pipelines/-/stats",
headers={"Authorization": f"Bearer {os.environ['DATAPLANE_TOKEN']}"},
)
response.raise_for_status()
print(response.json())
Response (200, 4xx, 5xx)
- Example
- Fields
- Errors
{
"items": [
{
"average_duration_ms": 0,
"latest_dataset_name": "<latest_dataset_name>",
"latest_destination_name": "<latest_destination_name>",
"latest_pipeline_run_at": "2026-01-01T00:00:00Z",
"latest_source_names": ["<latest_source_names>"],
"latest_status": "succeeded",
"pipeline_name": "<pipeline_name>",
"succeeded_pipeline_run_count": 0,
"success_ratio": 0,
"total_bytes_loaded": 0,
"total_duration_ms": 0,
"total_pipeline_run_count": 0,
"total_rows_extracted": 0,
"total_rows_loaded": 0
}
],
"limit": 0,
"next_cursor": "<next_cursor>",
"offset": 0,
"total": 0
}
| Field | Type | Description |
|---|---|---|
items | array of object | The rows of this page, in sort order. |
items[].average_duration_ms | integer or null | Mean duration_ms in the range, rounded; null when no run has a duration. |
items[].latest_dataset_name | string or null | Dataset of the most recent pipeline run in the time range. |
items[].latest_destination_name | string or null | Destination of the most recent pipeline run in the time range. |
items[].latest_pipeline_run_at | string (date-time) or null | When the most recent pipeline run in the time range started. |
items[].latest_source_names | array of string or null | Sources read by the most recent pipeline run in the time range. |
items[].latest_status | string or null | Status of the most recent pipeline run in the time range. One of: succeeded, failed. |
items[].pipeline_name | string | Name of the dlt pipeline. |
items[].succeeded_pipeline_run_count | integer | Pipeline runs in the range with status succeeded. |
items[].success_ratio | number | Succeeded ÷ total, from 0 to 1. |
items[].total_bytes_loaded | integer | Sum of normalized bytes (size of the normalized files) over succeeded runs in the time range. |
items[].total_duration_ms | integer | Sum of duration_ms over the runs in the range. Default: 0. |
items[].total_pipeline_run_count | integer | Pipeline runs in the range. |
items[].total_rows_extracted | integer | Sum of extracted rows over all runs in the range. |
items[].total_rows_loaded | integer | Sum of normalized rows over succeeded runs in the time range. |
limit | integer | The page size this page was fetched with. |
next_cursor | string or null | Cursor for the page after this one; null on the last. |
offset | integer | How many rows were skipped before this page. |
total | integer | Rows matching the filters, reported up to 10001. |
400Bad Request401Unauthorized403Forbidden500Internal Server Error
Each error returns the error body.
Get telemetry watermark
GET /telemetry/v1/workspaces/{workspace_id}/watermark
The most recent updated_at of any pipeline run in the workspace, or null when there are
none. Poll this and refetch lists only when it changes.
Request
- Parameters
- curl
- Python
Path parameters
| Name | Type | Description |
|---|---|---|
workspace_id | string (uuid) | ID of the workspace |
curl "$DATAPLANE_URL/telemetry/v1/workspaces/$WORKSPACE_ID/watermark" \
-H "Authorization: Bearer $DATAPLANE_TOKEN"
import os
import requests
response = requests.get(
"<dataplane_url>/telemetry/v1/workspaces/<workspace_id>/watermark",
headers={"Authorization": f"Bearer {os.environ['DATAPLANE_TOKEN']}"},
)
response.raise_for_status()
print(response.json())
Response (200, 4xx, 5xx)
- Example
- Fields
- Errors
{
"updated_at": "2026-01-01T00:00:00Z"
}
| Field | Type | Description |
|---|---|---|
updated_at | string (date-time) or null | When a pipeline run in the workspace was last recorded or updated; null when there are none. If it is older than the time range you read, empty results may mean telemetry is behind rather than that nothing ran. |
400Bad Request401Unauthorized403Forbidden500Internal Server Error
Each error returns the error body.