DQL pipe operators
Every operator in the pipe catalog, generated from the catalog the engine registers, so it cannot describe an operator that does not ship.
A pipe is an ordered chain of these operators applied to a stream of rows. They appear below in catalog order, which follows the shape of a typical pipe: source, filter, transform, aggregate, sort, side effect.
Column key01
| Column | Meaning |
| Live-safe | Pure and deterministic with default config, so it can run on a live-updating result set. |
| Pushable | Can fold into the SQL prefix. The planner makes the final call from the field types. |
| Requires | Host services the operator needs in its OpContext. Blank means it works anywhere. |
Index02
| Operator | Summary | Live-safe | Pushable | Requires |
filter | Keep rows that match a predicate | ✅ | ✅ | eval |
project | Select / alias columns | ✅ | ✅ | |
rename | Rename columns | ✅ | ✅ | |
drop | Remove columns | ✅ | — | |
compute | Add a computed column | ✅ | — | eval, formula |
transform | Compute multiple columns in one stage | ✅ | — | eval |
cast | Convert column types | ✅ | — | |
dropNulls | Drop rows with nulls in named columns | ✅ | ✅ | |
fillNulls | Replace nulls in named columns | ✅ | — | |
flatten | Unnest an array column | ✅ | — | |
unnestObject | Spread an object column into root keys | ✅ | — | |
nest | Group rows into nested arrays | ✅ | — | |
pivot | Rows → columns | ✅ | — | |
unpivot | Columns → rows | ✅ | — | |
distinct | Deduplicate rows | ✅ | — | |
dedupe | Keep one row per identity key | ✅ | — | |
sample | Random subset of rows | ✅ | — | |
assert | Fail the query when an expression is false | ✅ | — | eval |
timeBucket | Bucket rows into fixed time intervals | ✅ | — | |
gapfill | Fill missing time intervals | ✅ | — | |
sort | Order rows | ✅ | ✅ | |
limit | Cap row count | ✅ | ✅ | |
skip | Drop the first N rows | ✅ | ✅ | |
topPerGroup | Top N rows per partition | ✅ | — | |
groupBy | Set keys for the next aggregate | ✅ | ✅ | |
aggregate | Fold rows into groups | ✅ | ✅ | |
histogram | Bucket numeric values into equal-width bins | ✅ | — | |
window | Per-row computation within a partition | ✅ | — | |
lookup | Hash-join with another dataset | ✅ | — | classic |
asofJoin | Join on the closest timestamp | ✅ | — | classic |
crossJoin | Cartesian product with another dataset | ✅ | — | classic |
intersect | Rows present in every source | ✅ | — | classic |
except | Rows in left but not in right | ✅ | — | classic |
callFunction | Invoke a registered DTL function | — | — | functionRegistry |
callApp | Invoke a managed app | — | — | appCaller |
algo | Run a registered algorithm | — | — | algorithms |
branch | Per-row conditional sub-pipes | ✅ | — | eval |
merge | Fan-out then concat | ✅ | — | |
tap | Pass-through with a debug label | ✅ | — |
filter03
Keep rows that match a predicate
Live-safe by default: yes Pushable: yes Requires: eval
Filters rows by a WHERE clause. Plain field/op/value forms push down to SQL; DTL expr forms run in-memory.
| Field | Type | Required | Description |
where | any | yes | Conditions a row must satisfy to be kept. Use simple {field, op, value} shape for SQL-pushable filters, or {expr: "…"} for DTL expressions evaluated in-memory. |
Plain comparison
{
"op": "filter",
"where": {
"field": "level",
"op": "==",
"value": "ERROR"
}
}DTL expression
{
"op": "filter",
"where": {
"expr": "ts > now() - duration(\"1h\")"
}
}project04
Select / alias columns
Live-safe by default: yes Pushable: yes
Reduces each row to a chosen subset of columns, optionally renaming them.
| Field | Type | Required | Description |
select | array | Columns to keep, in order. Each entry is {field, as?} — set as to rename. | |
drop | array of string | Alternative to select — instead of listing what to keep, list what to remove. Mutually exclusive with select. |
Pick fields
{
"op": "project",
"select": [
{
"field": "id"
},
{
"field": "name"
}
]
}rename05
Rename columns
Live-safe by default: yes Pushable: yes
Rewrites column keys in-place. The map is from -> to.
| Field | Type | Required | Description |
map | object | yes | Object whose keys are the existing column names and whose values are the new names. Pairs not listed are left untouched. (input: column-rename-map) |
id → key
{
"map": {
"id": "key"
},
"op": "rename"
}drop06
Remove columns
Live-safe by default: yes Pushable: no
Deletes the named columns from each row.
| Field | Type | Required | Description |
columns | array of string | yes | Names of columns to remove from every row. |
Drop secrets
{
"columns": [
"password",
"secret"
],
"op": "drop"
}compute07
Add a computed column
Live-safe by default: yes Pushable: no Requires: eval, formula
Evaluates a DTL expression (kind:"expr") or Excel-style formula (kind:"formula") per row and stores the result under as.
| Field | Type | Required | Description |
as | string | yes | Column to write the computed value into. Overwrites any existing column with the same name. (input: column-output) |
kind | string | Which language expr / formula is in. Defaults to DTL expr. Default: expr. | |
expr | string | conditional {"kind":["expr",""]} | DTL expression evaluated against each row. Used when kind is expr. (input: dtl-expression) |
formula | string | conditional {"kind":["formula"]} | Spreadsheet formula evaluated against each row. Used when kind is formula. (input: formula) |
DTL expr
{
"as": "doubled",
"expr": "value * 2",
"op": "compute"
}Formula
{
"as": "tax",
"formula": "price * 0.1",
"kind": "formula",
"op": "compute"
}transform08
Compute multiple columns in one stage
Live-safe by default: yes Pushable: no Requires: eval
Like compute but takes a list. Entries evaluate in order and can reference earlier results. Use from for plain column copies and replace: true to drop everything not produced.
| Field | Type | Required | Description |
compute | array of object | yes | Ordered list of column definitions. Each entry uses expr (DTL) or from (column copy). |
drop | array of string | Optional. Columns to remove from the output after computation. | |
replace | boolean | When true, drop every column not produced by compute. Useful for reshape-and-rename in one step. Default: false. |
Add several columns
{
"compute": [
{
"as": "total",
"expr": "a + b"
},
{
"as": "ratio",
"expr": "a / b"
}
],
"op": "transform"
}Reshape
{
"compute": [
{
"as": "id",
"from": "_id"
},
{
"as": "score",
"expr": "wins / matches"
}
],
"op": "transform",
"replace": true
}cast09
Convert column types
Live-safe by default: yes Pushable: no
Coerce columns to int / float / bool / string / timestamp. onError chooses null (default) | skip | fail.
| Field | Type | Required | Description |
casts | array of object | yes | List of {field, to, onError?} rules applied in order. |
dropNulls10
Drop rows with nulls in named columns
Live-safe by default: yes Pushable: yes
When any is true (default) drops rows where ANY listed column is null; when false drops only when EVERY listed column is null.
| Field | Type | Required | Description |
columns | array of string | Columns inspected for null. Empty means every column on each row. | |
any | boolean | When true, drop a row if ANY listed column is null. When false, drop only when EVERY listed column is null. Default: true. |
fillNulls11
Replace nulls in named columns
Live-safe by default: yes Pushable: no
Methods: zero, value, lastValue, nextValue, mean. lastValue/nextValue require partitionBy + orderBy for deterministic forward/backward fill.
| Field | Type | Required | Description |
method | string | value uses the literal value; zero uses 0; lastValue carries the previous non-null forward; nextValue carries the next non-null backward; mean uses the column mean. Default: value. | |
value | any | conditional {"method":["value"]} | Used when method is value. Any JSON scalar. |
columns | array of string | Columns whose null cells are replaced. Empty means every column on each row. | |
partitionBy | array of string | conditional {"method":["lastValue","nextValue"]} | Required for lastValue / nextValue. Within each partition, ordering and carry semantics apply independently. |
orderBy | array | conditional {"method":["lastValue","nextValue"]} | Required for lastValue / nextValue to define what "previous" / "next" means within a partition. |
flatten12
Unnest an array column
Live-safe by default: yes Pushable: no
Emits one row per array element. When as is set, the element is stored under that key and the original field is preserved.
| Field | Type | Required | Description |
field | string | yes | Column whose array values are exploded into separate rows. (input: column) |
as | string | Optional. Column name to store each element under. When unset, the element replaces the array column on each row. (input: column-output) | |
indexAs | string | Optional. Column name to store the element's 0-based index in the source array. (input: column-output) | |
preserveEmpty | boolean | When true, rows whose array is empty or null still produce one output row (with the element column nil). Default drops them. Default: false. |
Unnest tags
{
"field": "tags",
"op": "flatten"
}unnestObject13
Spread an object column into root keys
Live-safe by default: yes Pushable: no
Useful for JSONB/metadata blobs whose nested keys you want as top-level columns.
| Field | Type | Required | Description |
field | string | yes | Column whose object value's keys are spread onto the root row. (input: column) |
prefix | string | Optional. Prepended to every spread key (e.g. m_ produces m_owner). (input: prefix) | |
drop | boolean | When true, the original object column is removed after spreading. Default: false. |
nest14
Group rows into nested arrays
Live-safe by default: yes Pushable: no
Inverse of flatten: emits one row per group with the remaining columns collected into an array under into.
| Field | Type | Required | Description |
by | array of string | yes | Partition keys; one output row is emitted per unique combination. |
into | string | yes | Name of the output column where the per-group array of nested records is stored. (input: column-output) |
include | array of string | Optional. Columns to include in each nested record. Defaults to every column not in by. |
pivot15
Rows → columns
Live-safe by default: yes Pushable: no
Each unique value in columnKey becomes a column. aggregate controls how to combine duplicates (sum/avg/count/min/max/first/last).
| Field | Type | Required | Description |
rowKeys | array of string | Columns whose distinct combinations identify each output row. | |
columnKey | string | yes | Column whose distinct values become the names of new columns. (input: column) |
valueField | string | yes | Column whose values populate the cells. (input: column) |
aggregate | string | How to combine multiple input rows that map to the same cell. Default: first. | |
fillValue | any | Value to use for output cells with no source row. Defaults to null. | |
prefix | string | Optional string prepended to every generated column name. (input: prefix) |
unpivot16
Columns → rows
Live-safe by default: yes Pushable: no
Melts named columns into name/value pairs (one output row per input row × valueCol).
| Field | Type | Required | Description |
idCols | array of string | Columns kept verbatim on every output row. Empty means every column not in valueCols. | |
valueCols | array of string | Columns whose values are unstacked into rows. Empty means every column not in idCols. | |
nameAs | string | yes | Output column that records the source column name. (input: column-output) |
valueAs | string | yes | Output column that records the cell value. (input: column-output) |
distinct17
Deduplicate rows
Live-safe by default: yes Pushable: no
When by is empty, uniqueness uses every column; otherwise only the named keys.
| Field | Type | Required | Description |
by | array of string | Columns whose combined values define a row's identity. Leave empty to deduplicate using every column. |
dedupe18
Keep one row per identity key
Live-safe by default: yes Pushable: no
Different from distinct (full-row equality): pick first or last row per key, with optional ordering.
| Field | Type | Required | Description |
by | array of string | yes | Columns whose combined values define a row's identity. |
keep | string | Whether to keep the first row encountered per identity (first) or the last (last). Combined with orderBy for deterministic results. Default: first. | |
orderBy | array | Optional. Sort applied within each identity group before applying keep. |
sample19
Random subset of rows
Live-safe by default: yes Pushable: no
Either n (target size) or ratio (0..1). seed makes output deterministic. Method: random (reservoir) | systematic (every k-th).
| Field | Type | Required | Description |
method | string | random uses reservoir sampling; systematic keeps every k-th row. Default: random. | |
n | integer | Sample size in rows. Mutually exclusive with ratio. | |
ratio | number | Fraction of input rows to keep, between 0 and 1. Mutually exclusive with n. | |
seed | integer | Optional integer seed for deterministic sampling. Same seed + same input ⇒ same output. |
assert20
Fail the query when an expression is false
Live-safe by default: yes Pushable: no Requires: eval
Runtime guardrail. scope=row evaluates per row; scope=overall checks once with count available.
| Field | Type | Required | Description |
scope | string | row evaluates the expression per row; overall evaluates once at the end with the row count available. Default: row. | |
expr | string | yes | DTL expression that must be truthy. Falsy results fail the query. (input: dtl-expression) |
message | string | Custom error message returned when the assertion fails. |
timeBucket21
Bucket rows into fixed time intervals
Live-safe by default: yes Pushable: no
Adds a column with the start of the bucket containing each row's timestamp. Pair with groupBy + aggregate for time-series rollups.
| Field | Type | Required | Description |
field | string | yes | Column carrying the row's timestamp. (input: column) |
interval | string | yes | Duration string for the bucket width — "5m", "1h", "1d". (input: duration) |
as | string | yes | Column to write the bucket-start timestamp into. (input: column-output) |
tz | string | Optional IANA timezone (e.g. America/New_York) used to align bucket boundaries. Defaults to UTC. (input: timezone) | |
origin | string | Optional RFC3339 anchor that defines where buckets start. Defaults to the Unix epoch. (input: timestamp) |
5-minute buckets
{
"as": "bucket",
"field": "ts",
"interval": "5m",
"op": "timeBucket"
}gapfill22
Fill missing time intervals
Live-safe by default: yes Pushable: no
Emits synthetic rows for time buckets missing from the input. Useful before charting sparse sensor streams.
| Field | Type | Required | Description |
field | string | yes | Column carrying the row's timestamp. (input: column) |
interval | string | yes | Duration string ("5m", "1h") describing the gap between expected timestamps. (input: duration) |
method | string | How to populate value columns on synthetic rows: zero, null, lastValue (carry forward), or value (use the literal value field). Default: null. | |
value | any | conditional {"method":["value"]} | Used when method is value. Any JSON scalar. |
from | string | Optional RFC3339 lower bound. Defaults to the earliest timestamp in the input. (input: timestamp) | |
to | string | Optional RFC3339 upper bound. Defaults to the latest timestamp in the input. (input: timestamp) | |
groupBy | array of string | Optional. Treat the input as multiple independent time series, gapfilling each partition separately. | |
carry | array of string | conditional {"method":["lastValue"]} | Columns whose value is copied from the most recent real row when method is lastValue. |
sort23
Order rows
Live-safe by default: yes Pushable: yes
Sorts by one or more keys. Direction defaults to asc.
| Field | Type | Required | Description |
by | array | yes | Ordered list of {field, dir} keys. Earlier entries are the primary sort; later entries break ties. |
Top 10 by ts
{
"by": [
{
"dir": "desc",
"field": "ts"
}
],
"op": "sort"
}limit24
Cap row count
Live-safe by default: yes Pushable: yes
| Field | Type | Required | Description |
n | integer | yes | Keep at most this many rows. Set to 0 to drop everything. |
skip25
Drop the first N rows
Live-safe by default: yes Pushable: yes
| Field | Type | Required | Description |
n | integer | yes | Number of rows to discard from the start of the input. Combined with limit gives offset/page semantics. |
topPerGroup26
Top N rows per partition
Live-safe by default: yes Pushable: no
Keeps the highest- (or lowest-) ranked N rows per group. With no partition, equivalent to top N overall.
| Field | Type | Required | Description |
n | integer | yes | How many rows to keep per partition (1 = top-1). |
partitionBy | array of string | Optional. Columns that split the input into partitions. Empty = single partition (top-N overall). | |
by | array | yes | Sort keys used to rank rows within each partition. The first key is primary; later keys break ties. |
groupBy27
Set keys for the next aggregate
Live-safe by default: yes Pushable: yes
On its own this is a pass-through. The planner pairs it with the immediately-following aggregate op.
| Field | Type | Required | Description |
keys | array of string | yes | Columns whose unique combinations define each group. The downstream aggregate folds rows within each combination. |
aggregate28
Fold rows into groups
Live-safe by default: yes Pushable: yes
Computes COUNT, SUM, AVG, MIN, MAX over groups defined by a preceding groupBy (or the whole stream when standalone).
| Field | Type | Required | Description |
keys | array of string | Optional. Same shape as groupBy.keys — when set, the aggregate uses these keys directly without a preceding groupBy stage. | |
aggs | array | yes | Ordered list of {fn, field, as} clauses (e.g. {fn: "SUM", field: "amount", as: "total"}). |
histogram29
Bucket numeric values into equal-width bins
Live-safe by default: yes Pushable: no
Replaces input rows with one row per bin: {binStart, binEnd, count}. Provide explicit min/max or let the op derive them.
| Field | Type | Required | Description |
field | string | yes | Column whose numeric values are bucketed. (input: column) |
bins | integer | yes | Number of equal-width bins to produce. |
min | number | Optional lower bound. Defaults to the minimum value seen in the input. | |
max | number | Optional upper bound. Defaults to the maximum value seen in the input. | |
asCount | string | Output column for the per-bin count. (input: column-output) Default: count. | |
asStart | string | Output column for each bin's lower edge. (input: column-output) Default: binStart. | |
asEnd | string | Output column for each bin's upper edge. (input: column-output) Default: binEnd. |
window30
Per-row computation within a partition
Live-safe by default: yes Pushable: no
row_number, rank, dense_rank, lag, lead, first_value, last_value. Output preserves input row order.
| Field | Type | Required | Description |
fn | string | yes | Which windowing function to compute per row. |
partitionBy | array of string | Columns that split the input into independent windows. Within each partition, the function is computed in orderBy order. | |
orderBy | array | Sort keys applied within each partition before the function runs. Required for ranking/lag/lead semantics. | |
field | string | conditional {"fn":["lag","lead","first_value","last_value"]} | Column the window function reads. Required for lag/lead/first_value/last_value; ignored for ranking functions. (input: column) |
offset | integer | Row offset for lag/lead. Defaults to 1 row. | |
default | any | Value to emit when the window function falls outside the partition (e.g. lag(1) on the first row). | |
as | string | yes | Column to write the window value into. (input: column-output) |
lookup31
Hash-join with another dataset
Live-safe by default: yes Pushable: no Requires: classic
Fetches the right side via a secondary classic query. Use cacheTtlMs to avoid re-fetching on every live update.
| Field | Type | Required | Description |
dataset | string | yes | Dataset name to fetch the join's right side from. (input: dataset) |
on | object | yes | Column names on each side that must equal for a match. |
mode | string | left keeps every left row; inner drops left rows with no match. Default: left. | |
as | string | Optional. When set, the matched right-side row is nested under this column instead of being flattened into the left row. (input: column-output) | |
select | array of string | Optional. Subset of right-side columns to merge in. Empty means all columns. | |
where | any | Optional WHERE clause applied to the right-side dataset before the join. | |
limit | integer | Optional. Cap the number of right-side rows fetched (useful when dataset is large). | |
cacheTtlMs | integer | Cache the right-side fetch for this many milliseconds. 0 disables caching. Useful when the same lookup runs many times under live mode. Default: 0. |
asofJoin32
Join on the closest timestamp
Live-safe by default: yes Pushable: no Requires: classic
For each left row, finds the right row with the closest timestamp on a matching key. Direction backward (default) | forward | nearest, with optional tolerance.
| Field | Type | Required | Description |
dataset | string | yes | Dataset to fetch the right side from. (input: dataset) |
leftTime | string | yes | Column on the streaming (left) side carrying the row's timestamp. (input: column) |
rightTime | string | yes | Column on the looked-up (right) side carrying the row's timestamp. (input: dataset-column) |
leftKey | string | Optional. Column on the left whose value must equal rightKey for a match. (input: column) | |
rightKey | string | Optional. Column on the right whose value must equal leftKey for a match. (input: dataset-column) | |
direction | string | backward finds the latest right row at or before the left row; forward the earliest at or after; nearest the absolute closest. Default: backward. | |
tolerance | string | Optional duration ("1m", "30s"). Drops matches further than this from the left row's timestamp. (input: duration) | |
as | string | Optional. When set, the matched right row is nested under this column. (input: column-output) | |
select | array of string | Optional subset of right-side columns to merge in. Empty means all columns. | |
where | any | Optional WHERE clause applied to the right-side dataset before the join. | |
limit | integer | Optional cap on right-side rows fetched. |
crossJoin33
Cartesian product with another dataset
Live-safe by default: yes Pushable: no Requires: classic
Output size is N × M — use sparingly. Right-side rows can be filtered with where and capped with limit.
| Field | Type | Required | Description |
dataset | string | yes | Dataset to fetch the cartesian-product right side from. (input: dataset) |
as | string | Optional. When set, each right row is nested under this column instead of being flattened into the left row. (input: column-output) | |
select | array of string | Optional subset of right-side columns to merge in. Empty means all columns. | |
where | any | Optional WHERE clause applied to the right-side dataset before the cross-join. | |
limit | integer | Optional cap on right-side rows. Strongly recommended to bound output size. |
intersect34
Rows present in every source
Live-safe by default: yes Pushable: no Requires: classic
Set intersection across N sub-pipes, identified by by keys (or full-row equality).
| Field | Type | Required | Description |
sources | array of object | yes | Two or more sub-pipes. Output rows are those present in every sub-pipe (under the chosen identity). |
by | array of string | Optional. When set, intersection compares only these columns. Empty falls back to full-row equality. |
except35
Rows in left but not in right
Live-safe by default: yes Pushable: no Requires: classic
| Field | Type | Required | Description |
left | object | yes | Source whose rows are kept when not present in right. |
right | object | yes | Source whose rows are subtracted from left. |
by | array of string | Optional. When set, set difference compares only these columns. Empty falls back to full-row equality. |
callFunction36
Invoke a registered DTL function
Live-safe by default: no Pushable: no Requires: functionRegistry
Calls a function from the function extension. pure: true declares the function side-effect-free and makes it live-safe.
| Field | Type | Required | Description |
name | string | yes | Fully qualified DTL function name (e.g. geo::lookup). (input: function-name) |
mode | string | perRow calls the function once per row; batch passes the whole row stream to the function once. Default: perRow. | |
pure | boolean | When true, asserts the function has no side effects so live mode can re-run it on each update. Default: false. | |
args | object | Object passed to the function. Values may reference row columns via $columnName. | |
literalArgs | boolean | When true, $column-style refs in args are passed verbatim instead of resolved against the row. | |
as | string | Column to store the function result under. (input: column-output) |
Per-row pure
{
"args": {
"x": "$value"
},
"name": "math::abs",
"op": "callFunction",
"pure": true
}callApp37
Invoke a managed app
Live-safe by default: no Pushable: no Requires: appCaller
Calls an external app via the runtime extension. Always non-live-safe; live subscriptions require dryRun: true.
| Field | Type | Required | Description |
appId | string | yes | Identifier of the managed app to invoke. (input: app-id) |
method | string | App method to call. Defaults to transform. Default: transform. | |
capability | string | Capability namespace the app must expose. Defaults to pipe_query. Default: pipe_query. | |
batch | boolean | When true, the entire row stream is sent to the app once. When false, the app is invoked per row. Default: true. | |
payload | object | Object merged into the app invocation payload alongside the rows. | |
dataset | string | Optional dataset name passed to the app for context. (input: dataset) |
algo38
Run a registered algorithm
Live-safe by default: no Pushable: no Requires: algorithms
Invokes a native or external algorithm from the shared catalog (e.g. minmax_scale, kmeans, robust_zscore). params are forwarded verbatim to the algorithm — see its descriptor for accepted keys. Live-safety depends on the chosen algorithm: pure ones (most ETL transforms) are live-safe; external/stateful ones are not.
| Field | Type | Required | Description |
name | string | yes | Identifier of a registered algorithm (e.g. minmax_scale, kmeans). Must exist in the algorithm catalog or the stage fails at build time. |
params | object | Algorithm-specific options passed through unchanged. Each algorithm documents its own keys in its catalog descriptor (e.g. minmax_scale takes column and as). |
Min-max scale a column
{
"name": "minmax_scale",
"op": "algo",
"params": {
"as": "v_scaled",
"column": "v"
}
}branch39
Per-row conditional sub-pipes
Live-safe by default: yes Pushable: no Requires: eval
Routes each row through then or else based on a DTL predicate. Live-safety propagates from the children.
| Field | Type | Required | Description |
when | string | yes | DTL expression evaluated per row. Truthy results take the then branch. (input: dtl-expression) |
then | array | yes | Stages applied to rows where the predicate is truthy. |
else | array | Optional. Stages applied to rows where the predicate is falsy. Empty drops the row. |
merge40
Fan-out then concat
Live-safe by default: yes Pushable: no
Runs each sub-pipe against a clone of the input and concatenates outputs.
| Field | Type | Required | Description |
sources | array of object | yes | List of sub-pipes. Each receives a clone of the input rows; outputs are concatenated in order. |
tap41
Pass-through with a debug label
Live-safe by default: yes Pushable: no
Records the row count against a label and returns rows unchanged.
| Field | Type | Required | Description |
label | string | Label that surfaces in stats.pipe[].label so this checkpoint is identifiable in the response. |