XpectraFlow docs
API reference

Channels

The channel list for a dataset, and why hypertableColName is the field that matters.

A channel is one measured quantity in a dataset — thrust, chamber pressure, battery voltage. It carries a name and a unit for humans, and a column name for machines.

Read this first

Every channel has two identifiers, and only one of them works for writing data.

FieldWhat it isUse it for
idA UUID for the channel rowUpdating the channel's metadata
hypertableColNameThe physical column, ch_0, ch_1, …Reading and writing values

hypertableColName — not id — is the address of the data.

POST /api/datasets/append takes ch_N (or the channel's name), and the gRPC ingest path matches TelemetryPoint.channel_id against the index N as a string, not the UUID. A producer that stores the UUID and sends it builds something that authenticates, validates, returns 200, and writes nothing at all. This is the single most common integration mistake against this API.

List channels

GET/api/datasets/channelsscope datasets:read

Prop

Type

curl -s "https://app.xpectraflow.com/api/datasets/channels?datasetId=$DATASET_ID&experimentId=$EXPERIMENT_ID" \
  -H "x-api-key: $XPECTRA_API_KEY"
[
  {
    "id": "c1a7e8b0-2f44-4d19-9c33-5b8e10f2a441",
    "name": "thrust",
    "unit": "kN",
    "dataType": "float",
    "hypertableColName": "ch_0"
  },
  {
    "id": "de92f31c-88a5-4c07-bb61-0a3d7e9c1b22",
    "name": "chamber_pressure",
    "unit": "bar",
    "dataType": "float",
    "hypertableColName": "ch_1"
  }
]

Pass experimentId if the dataset might be narrow. A narrow dataset — any MAVLink stream — declares no channels at registration; its signals are discovered from the data as it arrives. With experimentId present, this endpoint materialises that list before answering, so a flight nobody has opened in the console yet returns its real signals rather than an empty array.

Narrow channels are addressed by signal name (mavlink.ATTITUDE.roll), which is what appears in hypertableColName for that shape — there the signal is the address.

Create a channel

POST/api/datasets/channels/createscope datasets:write

Prop

Type

curl -s -X POST https://app.xpectraflow.com/api/datasets/channels/create \
  -H "x-api-key: $XPECTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "experimentId": "'"$EXPERIMENT_ID"'",
    "datasetId": "'"$DATASET_ID"'",
    "name": "nozzle_temp",
    "unit": "K",
    "dataType": "float"
  }'
{
  "id": "7b2c9d10-4e83-4a52-8f16-c0b91d3e5a77",
  "name": "nozzle_temp",
  "unit": "K",
  "dataType": "float",
  "hypertableColName": "ch_2"
}

The ch_N index is assigned by us — the next free one for the dataset — and returned so you know what to append against.

Declaring a channel does not create its column. This writes metadata; the underlying table is unchanged. If ch_2 does not physically exist yet, appending to it returns a 400 naming the channel.

To add a column to a live stream, re-register the stream with the full channel list — the ingest pipeline widens the table with the right type, partitioning and compression settings. Doing it from this side would produce a column that is subtly wrong forever.

In practice: declare all your channels at stream registration. This endpoint is for correcting an omission, not for building a schema incrementally.

Narrow datasets are refused with 409. Their signals are discovered, not declared.

Update a channel

POST/api/datasets/channels/updatescope datasets:write

Prop

Type

Fixes a name, a unit or a declared type. hypertableColName is not editable: it is where the data lives, and changing it would repoint the row at another channel's values rather than move anything.

dataType here is the declared type in the snapshot, not the physical column type. Correcting it changes how values are labelled and rendered; it does not convert data already written.

curl -s -X POST https://app.xpectraflow.com/api/datasets/channels/update \
  -H "x-api-key: $XPECTRA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "experimentId": "'"$EXPERIMENT_ID"'",
    "datasetId": "'"$DATASET_ID"'",
    "id": "'"$CHANNEL_ID"'",
    "name": "nozzle_temp",
    "unit": "degC",
    "dataType": "float"
  }'

Errors

StatuscodeWhen
400invalid_requestMissing datasetId, or a name outside 2–120 characters
403insufficient_scopeKey lacks datasets:read or datasets:write
404not_foundNo such dataset or channel, or not yours
409conflictDeclaring a channel on a narrow dataset

On this page