Ingest and query
Ingest (HTTP)
POST /api/v1/ingest accepts NDJSON (newline-delimited JSON). Each line is an object with:
- Preferred telemetry envelope:
metric(string, required)ts(integer, required)value(number, optional)fields(object, optional): numeric-only sibling metricslabels(object, optional)kind,unit,description(optional metric metadata)
series(string, required)ts(integer, required)value(number, optional)fields(object, optional): ifvalueis missing, the first numeric field is usedtags(object, optional): converted to a JSON string and hashed into the series id (see Series IDs)
Example:
curl -XPOST localhost:8080/api/v1/ingest --data-binary $'{"metric":"requests_total","ts":1694300000,"value":42,"labels":{"service":"api","host":"edge-1"},"kind":"counter","unit":"requests"}\\n'
Response:
{"ingested":1}
Query range (HTTP)
POST JSON
POST /api/v1/query/range takes JSON:
{"metric":"requests_total","labels":{"service":"api","host":"edge-1"},"start":1694290000,"end":1694310000}
You can also pass series_id (integer) instead of series.
The response is a JSON array of points:
[{"ts":1694300000,"value":24.2}]
GET query parameters
GET /api/v1/query/range supports:
series_id=<u64>(preferred) orseries=<string>metric=<string>labels=<string>(canonical JSON object)tags=<string>(defaults to{}) — passed into the series hash as-isstart=<i64>(required)end=<i64>(required)
Example:
curl 'http://localhost:8080/api/v1/query/range?series=weather.room1&start=1694290000&end=1694310000'
Discover metrics and series (HTTP)
POST /api/v1/metrics/find returns metric descriptors such as metric, kind, series_count, label_keys, and time bounds.
POST /api/v1/series/find returns exact series descriptors for one metric family, including canonical labels.
POST /api/v1/labels/values returns known values for one label key, optionally scoped to a metric family.
POST /api/v1/metrics/health returns per-metric operator health such as missing metadata, inactive series counts, and last-seen timestamps.
Compare windows (HTTP)
Use POST /api/v1/query/compare to compare one exact series across two time windows:
{
"metric":"requests_total",
"labels":{"service":"api","host":"edge-1"},
"start":1694300000,
"end":1694303600,
"baseline_start":1694296400,
"baseline_end":1694300000,
"aggregate":"delta"
}
For counters, delta is reset-aware, which makes this endpoint useful for before/after deploy checks.
Write and query annotations (HTTP)
Use POST /api/v1/annotations/write to persist deploy markers, incident notes, or maintenance windows:
{
"kind":"deploy",
"title":"api rollout",
"metric":"requests_total",
"labels":{"service":"api"},
"start":1694300100,
"message":"rolled out build 2026.04.06"
}
Use POST /api/v1/annotations/query to fetch those markers for a time range and metric scope.
Find series by tags (legacy HTTP)
POST /api/v1/query/find accepts JSON:
tags(object): exact-match on tag key/value pairsop(string, optional):"and"(default) or"or"for combining tag filters
Response is an array of matching series_id values.
sydraQL (HTTP)
POST /api/v1/sydraql expects the request body to be plain text containing a sydraQL query.
See also:
Response shape:
columns: array of{name,type,nullable}rows: array of row arraysstats: timings and operator stats
Ingest/query via CLI
sydradb ingest reads NDJSON from stdin and writes to the local WAL:
cat points.ndjson | ./zig-out/bin/sydradb ingest
sydradb query <series_id> <start_ts> <end_ts> prints ts,value rows:
./zig-out/bin/sydradb query 123 1694290000 1694310000
See also: