API & TimeseriesQL Reference¶
Core HTTP routes for writes, queries, and health, plus TimeseriesQL. Authentication (which routes need credentials, 401 vs 403 on internal APIs, Basic/Token/u&p) is covered in Authentication. For cluster, replication, Raft, and internal route lists, see Cluster, replication, and internal routes below; the authoritative list is src/adapters/http/router.rs.
HTTP API¶
Every response carries these headers:
| Header | Value |
|---|---|
X-Hyperbytedb-Version | The version, e.g. 0.9.3-beta (from 0.9.3) |
X-Influxdb-Version | HyperbyteDB-<version>, for InfluxDB clients and tools |
X-Influxdb-Build | OSS, for InfluxDB clients and tools |
Request-Id | UUID per request |
X-Request-Id | Same UUID |
POST /write¶
Write time-series data using InfluxDB line protocol.
Query parameters:
| Parameter | Required | Default | Description |
|---|---|---|---|
db | Yes | — | Target database name |
rp | No | Default RP | Retention policy |
precision | No | ns | Timestamp precision: ns, us/u, ms, s |
u | No | — | Username (when auth enabled) |
p | No | — | Password (when auth enabled) |
Supports: Content-Encoding: gzip for compressed payloads.
Response codes:
| Code | Meaning |
|---|---|
| 204 | Success (empty body) |
| 400 | Parse error, or partial write (points with a field type conflict dropped, the rest stored) |
| 401 | Authentication failed (missing/invalid credentials when auth is enabled) |
| 404 | Database not found |
| 422 | Cardinality limit exceeded |
| 500 | Internal error |
| 503 | Node draining/syncing (cluster mode) |
GET/POST /query¶
Execute TimeseriesQL queries.
Query parameters:
| Parameter | Required | Default | Description |
|---|---|---|---|
q | Yes | — | TimeseriesQL query string |
db | Depends | — | Required for data queries |
epoch | No | RFC3339 | Timestamp format: ns, us/u, ms, s |
pretty | No | false | Pretty-print JSON |
chunked | No | false | Stream results per statement |
params | No | — | JSON object for $param bind parameters |
Accept header:
| Value | Response format |
|---|---|
application/json (default) | JSON |
text/csv or application/csv | CSV |
POST body: Parameters can be sent as application/x-www-form-urlencoded. Body parameters override query string parameters.
GET/HEAD /ping¶
Returns 204 No Content with version headers. Compatible with InfluxDB client library connection tests.
GET /health¶
Returns JSON health status:
GET /metrics¶
Prometheus-format metrics. See Administration for the full metric catalog.
GET/DELETE /api/v1/statements¶
- GET — Returns recently executed statement summaries (when
statement_summary.enabled = true). - DELETE — Resets the statement summary ring buffer.
Cluster-only endpoints (subset)¶
These are available when cluster mode is enabled and are often used with internal automation or curl.
| Endpoint | Method | Description |
|---|---|---|
/cluster/metrics | GET | Cluster mode info, node address, peer list |
/cluster/nodes | GET | All nodes with a self flag |
/internal/drain | POST | Initiate graceful node drain |
Cluster, replication, and internal routes¶
The following apply when the corresponding features are compiled in and enabled. When [auth] enabled = true, these routes require admin credentials (same u/p, Basic, or Token as elsewhere); a logged-in non-admin user receives 403. If auth is off, the HTTP layer does not check credentials—use network controls in production. Details: Authentication.
Cluster / peer (non-Raft)
| Endpoint | Method | Description |
|---|---|---|
/internal/replicate | POST | Ingest-sized write replication from peer |
/internal/replicate-mutation | POST | Schema/mutation replication |
/internal/membership | GET | Membership view |
/internal/membership/join | POST | Join cluster |
/internal/membership/leave | POST | Leave cluster |
/internal/sync/manifest | GET | Sync manifest (metadata + WAL tail summary) |
/internal/sync/metadata | GET | Metadata snapshot for startup/reconnect sync |
/internal/sync/wal | GET | WAL entries for catch-up |
/internal/sync/trigger | POST | Trigger reconnect sync on a peer |
Raft (when Raft is enabled)
| Endpoint | Method | Description |
|---|---|---|
/internal/raft/vote | POST | Raft RPC |
/internal/raft/append | POST | Raft RPC |
/internal/raft/snapshot | POST | Raft RPC |
/cluster/raft/metrics | GET | Raft metrics |
/cluster/raft/add-learner | POST | Add learner node |
/cluster/raft/change-membership | POST | Change membership |
/cluster/raft/client-write | POST | Client write through Raft |
/cluster/leader | GET | Current Raft leader |
/cluster/membership/add-node | POST | Operator-style add node |
/cluster/membership/remove-node | POST | Operator-style remove node |
Series sharding (when [sharding] enabled = true)
| Endpoint | Method | Description |
|---|---|---|
/internal/shard/bootstrap | POST | Register a measurement region (Raft leader) |
/internal/shard/write | POST | Apply forwarded line protocol for a region |
/internal/shard/query | POST | Execute region-scoped ClickHouse SQL |
/internal/shard/metadata | POST | Region-scoped SHOW TAG KEYS/VALUES/SERIES |
/internal/shard/delete | POST | Physical delete cleanup for a region |
/internal/shard/transfer | POST | Receive WAL export during region transfer |
/internal/shard/heartbeat | POST | Region stats to the Raft leader |
/internal/shard/map | GET | Read-only shard map snapshot |
See Deep Dive: Clustering — Series Sharding for scatter, failover, and epoch semantics.
POST /api/v1/chdb¶
Execute raw ClickHouse SQL against the embedded chDB engine. Admin-only when auth is enabled.
Query parameters:
| Parameter | Required | Default | Description |
|---|---|---|---|
db | Yes | — | Target database name |
Body: Raw ClickHouse SQL as application/x-www-form-urlencoded with key q.
GET /health/ready¶
Readiness probe: verifies the query engine (chDB) is usable. Used for Kubernetes readiness checks (see Installation).
TimeseriesQL Reference¶
SELECT¶
SELECT <field_expression>[, ...] FROM <measurement>
[INTO <target_measurement>]
[WHERE <condition>]
[GROUP BY time(<interval>[, <offset>])[, <tag_key>...]]
[ORDER BY time [ASC|DESC]]
[LIMIT <n>] [OFFSET <n>]
[SLIMIT <n>] [SOFFSET <n>]
[fill(<option>)]
[TZ('<timezone>')]
Field expressions: - Column references: "usage_idle", * - Aggregate functions: mean("value"), count(*), etc. - Transform functions: derivative(mean("value"), 1s), etc. - Arithmetic: mean("a") * 100 + mean("b") - Aliases: mean("value") AS avg_value - Type hints: "host"::tag, "value"::field
Column names follow InfluxQL: an alias wins; otherwise a function call is named after the function (mean("value") → mean), an expression after the fields and functions in it ("a" + "b" → a_b), and a repeated name gets _1, _2 (mean("a"), mean("b") → mean, mean_1).
The time column is always first. Raw selects return each point's time and GROUP BY time() returns each bucket's start. An aggregate without GROUP BY time() returns one row stamped 1970-01-01T00:00:00Z, whatever the WHERE time range; a lone first(), last(), max() or min() returns the selected point's own time.
FROM clause: - Single: FROM "cpu" - Fully-qualified: FROM "mydb"."myrp"."cpu" - Regex: FROM /^cpu.*/ - Subquery: FROM (SELECT mean("value") FROM "cpu" GROUP BY time(1h))
WHERE Operators¶
| Operator | Description | Example |
|---|---|---|
= | Equals | "host" = 'server01' |
!=, <> | Not equals | "host" != 'server02' |
<, <=, >, >= | Comparison | time > now() - 1h |
AND, OR | Logical | "host" = 'a' AND time > now() - 1h |
=~ | Regex match | "host" =~ /^us-.*/ |
!~ | Regex not match | "host" !~ /^eu-.*/ |
Time Expressions¶
now()— current server time- Duration literals:
1ns,5u,100ms,30s,15m,2h,7d,4w - RFC3339:
'2024-01-01T00:00:00Z'
Fill Options¶
| Fill | Behavior |
|---|---|
fill(null) | Empty buckets filled with NULL |
fill(none) | Empty buckets omitted |
fill(0) | Empty buckets filled with 0 (or any numeric value) |
fill(previous) | Forward-fill from last known value |
fill(linear) | Linear interpolation between known values |
Aggregate Functions¶
| Function | Description |
|---|---|
MEAN(field) | Arithmetic mean |
MEDIAN(field) | Median value |
COUNT(field) | Row count |
SUM(field) | Sum of values |
MIN(field) | Minimum value |
MAX(field) | Maximum value |
FIRST(field) | Value at earliest timestamp |
LAST(field) | Value at latest timestamp |
PERCENTILE(field, N) | Nth percentile |
SPREAD(field) | max - min |
STDDEV(field) | Standard deviation (population) |
MODE(field) | Most frequent value |
DISTINCT(field) | Unique values |
Selector Functions¶
These return up to N stored points per group (each GROUP BY time() bucket and tag set), each at its own time, in time order.
| Function | Description |
|---|---|
TOP(field, N) | The N largest values; the earliest point wins a tie |
TOP(field, tag[, tag...], N) | The N largest values, at most one per tag-value combination; the tags are returned as columns |
BOTTOM(field, N) / BOTTOM(field, tag[, tag...], N) | The N smallest values, likewise |
SAMPLE(field, N) | N points picked at random |
Other fields and tags may be selected beside them (SELECT top("value", 3), "host"), taken from the same points, but not other functions. LIMIT and OFFSET apply to the points returned.
A raw field cannot be grouped by time: SELECT "value" ... GROUP BY time(1m) fails with GROUP BY requires at least one aggregate function, as in InfluxDB.
Transform Functions¶
| Function | Description |
|---|---|
DERIVATIVE(field_or_agg, unit) | Rate of change per unit |
NON_NEGATIVE_DERIVATIVE(field_or_agg, unit) | Rate of change, clamping negatives to 0 |
DIFFERENCE(field_or_agg) | Difference from previous value |
NON_NEGATIVE_DIFFERENCE(field_or_agg) | Non-negative difference |
MOVING_AVERAGE(field_or_agg, N) | N-point moving average |
CUMULATIVE_SUM(field_or_agg) | Running total |
ELAPSED(field, unit) | Time elapsed since previous point |
Transforms can wrap aggregates:
SELECT non_negative_derivative(mean("bytes_recv"), 1s) FROM "net"
WHERE time > now() - 1h GROUP BY time(10s)
SHOW Commands¶
SHOW DATABASES
SHOW MEASUREMENTS [ON <database>]
SHOW TAG KEYS [FROM <measurement>]
SHOW TAG VALUES [FROM <measurement>] WITH KEY = "<key>"
SHOW TAG VALUES [FROM <measurement>] WITH KEY =~ /<regex>/
SHOW TAG VALUES [FROM <measurement>] WITH KEY IN ("<key1>", "<key2>")
[WHERE <tag conditions>] [LIMIT <n>] [OFFSET <n>]
-- tag conditions: =, !=, =~, !~, AND, OR,
-- with or without ::tag; time is ignored
SHOW FIELD KEYS [FROM <measurement>]
SHOW SERIES [FROM <measurement>]
SHOW SERIES [EXACT] CARDINALITY [ON <db>] [FROM <measurement>] [WHERE <tag condition>]
[LIMIT n] [OFFSET n]
SHOW MEASUREMENT [EXACT] CARDINALITY [ON <db>] [FROM <measurement>]
[WITH MEASUREMENT <op> <name|/regex/>]
[WHERE <tag condition>]
SHOW TAG KEY [EXACT] CARDINALITY [ON <db>] [FROM <measurement>] [WHERE <tag condition>]
SHOW TAG VALUES [EXACT] CARDINALITY [ON <db>] [FROM <measurement>] [WITH KEY <op> <key>]
[WHERE <tag condition>]
SHOW FIELD KEY [EXACT] CARDINALITY [ON <db>] [FROM <measurement>]
SHOW RETENTION POLICIES [ON <database>]
SHOW USERS
SHOW GRANTS FOR <user> -- admin; database, privilege
SHOW CONTINUOUS QUERIES
Cardinality¶
The CARDINALITY statements count what the matching SHOW would list, and the counts are always exact. Without a WHERE, they come from the metadata caches without scanning anything: the series index (on a sharded cluster, each region's peer counts its own range, so a replicated series counts once), the tag value counts, and the measurement metadata. A WHERE is matched against each series' tags, like SHOW TAG VALUES ... WHERE.
The output follows InfluxDB 1.x. SHOW SERIES CARDINALITY with no FROM or WHERE, and SHOW MEASUREMENT CARDINALITY with no FROM, WITH or WHERE, return one row under cardinality estimation. InfluxDB reports an estimate there; HyperbyteDB reports the exact count. EXACT, or any filter, returns count instead, with one series per measurement, and measurements with a count of zero are left out. SHOW FIELD KEY CARDINALITY refuses WHERE, because fields aren't indexed by tag.
> SHOW SERIES CARDINALITY ON telegraf
cardinality estimation
----------------------
1520
> SHOW SERIES EXACT CARDINALITY ON telegraf FROM cpu
name: cpu
count
-----
304
DDL Statements¶
CREATE DATABASE "<name>"
DROP DATABASE "<name>"
DROP MEASUREMENT "<name>"
CREATE RETENTION POLICY "<name>" ON "<db>"
DURATION <duration> REPLICATION <n> [SHARD DURATION <duration>] [DEFAULT]
ALTER RETENTION POLICY "<name>" ON "<db>"
DURATION <duration> [REPLICATION <n>] [DEFAULT]
DROP RETENTION POLICY "<name>" ON "<db>"
CREATE USER "<name>" WITH PASSWORD '<password>'
DROP USER "<name>"
SET PASSWORD FOR "<name>" = '<password>'
GRANT READ | WRITE | ALL ON "<db>" TO "<user>"
REVOKE READ | WRITE | ALL ON "<db>" FROM "<user>"
GRANT ALL PRIVILEGES TO "<user>" -- make admin
REVOKE ALL PRIVILEGES FROM "<user>"
CREATE CONTINUOUS QUERY "<name>" ON "<db>"
[RESAMPLE EVERY <interval> FOR <interval>]
BEGIN <select_into_statement> END
DROP CONTINUOUS QUERY "<name>" ON "<db>"
CREATE MATERIALIZED VIEW "<name>" ON "<db>"
AS <select_into_statement> -- every column needs AS "<name>"
DROP MATERIALIZED VIEW "<name>" ON "<db>"
SHOW MATERIALIZED VIEWS
SET <setting> = <integer> | TRUE | FALSE | '<text>' | DEFAULT
-- admin; applied on every node at once
SHOW SETTINGS -- name, value, source, config, description
Runtime settings¶
A SET overrides the config file on every node. source in SHOW SETTINGS is set (an override), config (the node's config file) or auto (derived from the node's CPUs). Each node keeps its own config value underneath, so DEFAULT returns every node to its own.
| Setting | Values | Config key | Takes effect |
|---|---|---|---|
log_level | filter text, e.g. 'info', 'hyperbytedb=debug,info' | logging.level (or RUST_LOG) | next log line |
query_pool_size | 1-128 | chdb.query_pool_size, else CPUs + 1 | pool resizes at once |
write_pool_size | 1-128 | chdb.write_pool_size | pool resizes at once |
max_concurrent_queries | 0-100000 (0: unlimited) | server.max_concurrent_queries | next query; running ones finish under the old cap |
query_timeout_secs | 1-86400 | server.query_timeout_secs | next query |
max_inflight_writes | 1-1000000 | server.max_inflight_writes, else 32 per CPU | next request; a shrink takes permits back as writes finish |
rate_limit_per_second | 0 or more (0: off) | rate_limit.max_requests_per_second when rate_limit.enabled | next request; turning it on starts with a full bucket |
max_tag_values_per_measurement | 0 or more (0: unlimited) | cardinality.max_tag_values_per_measurement | next new series |
max_measurements_per_database | 0 or more (0: unlimited) | cardinality.max_measurements_per_database | next new measurement |
flush_interval_secs | 1-3600 | flush.interval_secs | after the current wait |
add_peer_proposals_enabled | TRUE/FALSE | sharding.add_peer_proposals_enabled | next scheduler tick |
remove_peer_proposals_enabled | TRUE/FALSE | sharding.remove_peer_proposals_enabled | next scheduler tick |
peer_heal_enabled | TRUE/FALSE | sharding.peer_heal_enabled | next scheduler tick |
schedule_limit | 1-256 | sharding.schedule_limit | at once; running copies finish |
movement_budget_bytes_per_sec | 0 or more (0: unlimited) | sharding.movement_budget_bytes_per_sec | next scheduler tick |
region_split_series | 1 or more | sharding.region_split_series | next split check |
region_max_series | 1 or more | sharding.region_max_series | next split check |
region_merge_series | 0 or more | sharding.region_merge_series | next merge check |
split_merge_interval_secs | 1-86400 | sharding.split_merge_interval_secs | next split check |
bootstrap_regions_per_node | 0-16 (0: one region) | sharding.bootstrap_regions_per_node | next new measurement |
The cardinality limits apply to client writes. Region copies, replicas and node syncs copy data that already exists, so a lower limit never refuses them.
The scheduler settings only do anything on a sharded cluster; elsewhere SHOW SETTINGS lists them without a value. Settings that need a restart anyway (listen addresses, data paths, Raft timing, replication factor, TLS, auth) are not runtime settings.
SET is replicated through Raft and stored, so it survives a restart and reaches nodes that join later. SET <setting> = DEFAULT removes the override. Do not run SET while a rolling upgrade from a version without it is in progress: nodes on the older build cannot decode it.
DELETE¶
DELETE marks data with tombstone records. Tombstoned data is excluded from queries at read time; underlying MergeTree rows are not rewritten in place.
InfluxDB v1 Compatibility Matrix¶
What works identically¶
- Line protocol write format and semantics
/writeand/queryendpoint behavior/pingresponse for client library connection tests- JSON response shapes (
{"results":[...]}) epochparameter for timestamp formatting- Authentication methods (query params, Basic, Token)
- Multiple statement queries (
;separator) - All SHOW commands listed above
- CREATE/DROP DATABASE, retention policy management
- Gzip write support
- Chunked query responses
Known Differences¶
| Area | Difference |
|---|---|
| Query engine | ClickHouse (chDB) internally. Minor floating-point edge cases at bucket boundaries. |
| Storage format | chDB MergeTree tables instead of TSM shards. No direct TSM import. |
| fill(previous/linear) | Via ClickHouse INTERPOLATE; may differ at series boundaries. |
| SELECT INTO with regex | Not supported. Use explicit measurement names. |
| Permissions | Admin users, plus GRANT/REVOKE READ, WRITE or ALL per database, as in InfluxDB v1. |
| Subscriptions | Not supported. |
Recommendations¶
- Use
fill(null)orfill(none)when exact InfluxDB behavior is required at time boundaries. - Test
fill(previous)andfill(linear)results for critical dashboards. - Avoid
SELECT INTOwith regex measurement sources. - Plan authorization around admin/non-admin roles only.
See Also¶
- Authentication — Enabling auth, public endpoints,
401/403on internal routes - Basic operations — Getting started with writes and queries
- Advanced features — Clustering, CQs, TLS
- Configuration — All settings reference