API
Namespace metadata
Request
metadata = await client.get_namespace_metadata("products")metadata, err := client.GetNamespaceMetadata(ctx, "products")const metadata = await client.getNamespaceMetadata("products");curl "$LAYER_GATEWAY_URL/v2/namespaces/products/metadata" \
-H "Authorization: Bearer $LAYER_GATEWAY_API_KEY" {
// Proxied from Turbopuffer verbatim
"schema": { },
"approx_row_count": 12500,
"approx_logical_bytes": 48800000,
"created_at": "2026-03-15T10:30:45Z",
"updated_at": "2026-05-12T18:49:00Z",
"last_write_at": "2026-05-12T18:48:30Z",
"index": { "status": "up-to-date" },
// Layer enhancement
"layer": {
"stable_as_of": 1715600400000,
"is_stable": true,
"indexed": true,
"index_lag_rows": 0
}
}
The layer block
| Field | Meaning |
|---|---|
stable_as_of | Epoch-ms watermark from the most recent stable poll. Null on cold start before the watcher has observed a stable namespace. |
is_stable | Whether the most recent poll observed index.status == "up-to-date". False on cold start, true once the watcher catches up. |
indexed | Whether every row in the namespace carries an indexed vector. True once the snapshot’s indexed-vector row count has caught up to the namespace row count; false while rows are still awaiting their first index, as during a bulk load or a pipeline mid-flight. Null for FTS-only namespaces, which have no vector column to reconcile. |
index_lag_rows | Count of rows present in the namespace that do not yet have an indexed vector. Zero when indexed is true. Reconciled from the most recent snapshot, so it trails live writes by the snapshot cadence. |
A read for a namespace that does not exist returns upstream’s 404, matching Turbopuffer’s own metadata endpoint.
is_stable is the current signal — it drives the per-query filter-skip
decision on the query path. stable_as_of is the historical watermark
— the cut a filtered query would apply.
After a namespace is observed stable, the watcher refreshes this watermark
on the stable-tier cadence (CONSISTENCY_STABLE_POLL_INTERVAL_MS, default
60000 ms). Writes re-arm the fast tier, so active namespaces are polled on
CONSISTENCY_POLL_INTERVAL_MS.
indexed answers a different question than is_stable. is_stable reports
whether the upstream index has caught up on the rows it has seen, which is
what read-after-write depends on. indexed reports whether every row that
should be present is present and queryable, which is what a bulk load or a
pipeline needs to know it has finished: rows can be
staged and counted before their vectors are indexed, so a namespace can read
is_stable: true while indexed: false with a non-zero index_lag_rows.
The reconciliation runs against the latest snapshot,
so indexed advances on the snapshot cadence rather than per write.
For snapshot history derived from these freshness signals, see Snapshots.
List namespaces
GET /v2/namespaces is a Layer-only augmented listing. It pages the
upstream namespace list and enriches each row with stability and cache
signals. It is the endpoint the dashboard’s inventory view reads.
namespaces = await client.list_namespaces(prefix="prod", page_size=100)namespaces, err := client.ListNamespaces(ctx, &hevlayer.ListNamespacesParams{
Prefix: "prod",
PageSize: 100,
})const namespaces = await client.listNamespaces({
prefix: "prod",
pageSize: 100,
});curl "$LAYER_GATEWAY_URL/v2/namespaces?prefix=prod&page_size=100" \
-H "Authorization: Bearer $LAYER_GATEWAY_API_KEY" {
"namespaces": [
{
"name": "products",
"row_count": 12500,
"size_bytes": 48800000,
"stable_as_of_ms": 1715600400000,
"is_stable": true,
"index": { "status": "up-to-date" },
"cache_state": {"state": "warm", "warm_inflight": false},
"last_write_ms": 1715600399000,
"shadow": false,
"labels": {}
}
],
"next_cursor": "..."
}
Each row carries freshness signals derived from that row’s metadata fetch.
is_stable is true when index.status is "up-to-date", false when it is
"updating", and omitted when metadata has no index signal or the fetch
failed. stable_as_of_ms is set to the metadata observation time for rows
reported up to date.
indexed and index_lag_rows live on
GET /v2/namespaces/{namespace}/metadata, where the gateway can do the
snapshot lookup for one namespace without adding object-store reads to the
high-fanout list path.
index is Turbopuffer’s indexing state, passed through verbatim:
| Field | Meaning |
|---|---|
index.status | "updating" or "up-to-date". |
index.unindexed_bytes | Write-ahead-log bytes not yet indexed. Present only while updating (omitted once caught up). Unindexed data is still searched by queries, so a non-zero value means behind, but serving — watch it fall to confirm indexing is draining rather than wedged. |
Listing is read-only and does not register namespaces with the consistency watcher. Write traffic and snapshot facet configuration register the namespaces that need durable watermarks.
| Query param | Purpose |
|---|---|
prefix | Restrict to namespaces whose name starts with this string. |
cursor | Pagination cursor from a prior next_cursor. |
page_size | Page size; the upstream list page is capped at 1000. |
A per-row metadata failure degrades to a row with metadata_error set
rather than dropping the namespace, so the list stays complete even when a
single namespace’s metadata call fails. Responses are served from a
short-TTL cache (NAMESPACE_LIST_CACHE_TTL_MS, default 10000) so
dashboard polling does not fan out a metadata call per namespace per
refresh.