API reference · v0.1.0

Logs HTTP API

Loki-compatible LogQL query and log ingestion API. Generated from the OpenAPI 3.1 document shipped with the server.

Base URLs

Writers serve every /write route and readers serve every /read route. The operator creates a Service for each, named after the Logs resource. Any writer accepts any write and forwards it to the owning shard, so plain round-robin load balancing is enough.

Authentication

Requests use HTTP basic auth. Each NamespaceAuthentication grants one username read or write on one namespace, with the password held in a Secret. Probes and self-metrics are unauthenticated.

Namespaces

Data is partitioned into tenant namespaces, and every data route carries one as /read/ns/{namespace} or /write/ns/{namespace}. A Loki data source pointed at http://logs-reader.telemetry:3100/read/ns/default works unchanged.

Errors and backpressure

Errors use the Loki error envelope with a 4xx or 5xx status. When object storage falls behind, writers reject new batches with 429 and a Retry-After header; configure your agent to retry them.
Resource

query

LogQL evaluation. Every read route is namespace-scoped under /read/ns/{namespace}.

Instant query

GET/read/ns/{namespace}/loki/api/v1/query
Evaluates a LogQL expression at a single point in time. Log selectors return streams of entries; metric queries such as rate() or count_over_time() return a vector.

Path parameters

  • namespacestringrequired
    Configured tenant namespace

Query parameters

  • querystringrequired
    LogQL expression
  • timestring
    Evaluation timestamp as RFC 3339 or Unix nanoseconds. Defaults to now.
  • limitinteger
    Maximum number of results to return.
    Minimum 0
  • directionstring
    forward or backward

Responses

  • 200Loki query responseapplication/json
    ›LokiEnvelope
    • dataobjectrequired
    • statusstringrequired
  • 400Invalid queryapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 401Authentication required
  • 404Unknown namespace
Request
curl -G http://logs-reader.telemetry:3100/read/ns/default/loki/api/v1/query \
  -u reader:$PASSWORD \
  --data-urlencode 'query={app="checkout"} |= "error" | logfmt | duration > 250ms' \
  --data-urlencode 'limit=100'
Response · 200
{
  "status": "success",
  "data": {
    "resultType": "streams",
    "result": [
      {
        "stream": {
          "app": "checkout",
          "env": "prod"
        },
        "values": [
          [
            "1791464400000000000",
            "level=error msg=\"payment declined\" duration=412ms"
          ]
        ]
      }
    ],
    "stats": {}
  }
}

Instant query (form)

POST/read/ns/{namespace}/loki/api/v1/query
Evaluates a LogQL expression at a single point in time. Log selectors return streams of entries; metric queries such as rate() or count_over_time() return a vector.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Form fields

application/x-www-form-urlencoded
  • querystringrequired
    LogQL expression
  • timestring
    Evaluation timestamp as RFC 3339 or Unix nanoseconds. Defaults to now.
  • limitinteger
    Maximum number of results to return.
    Minimum 0
  • directionstring
    forward or backward

Responses

  • 200Loki query responseapplication/json
    ›LokiEnvelope
    • dataobjectrequired
    • statusstringrequired
Request
curl -X POST "http://logs-reader.telemetry:3100/read/ns/default/loki/api/v1/query" \
  -u reader:$PASSWORD \
  --data-urlencode 'query={app="checkout"} |= "error" | logfmt | duration > 250ms' \
  --data-urlencode 'limit=100'
Response · 200
{
  "status": "success",
  "data": {
    "resultType": "streams",
    "result": [
      {
        "stream": {
          "app": "checkout",
          "env": "prod"
        },
        "values": [
          [
            "1791464400000000000",
            "level=error msg=\"payment declined\" duration=412ms"
          ]
        ]
      }
    ],
    "stats": {}
  }
}

Range query

GET/read/ns/{namespace}/loki/api/v1/query_range
Evaluates a LogQL expression over a time range. Log queries return up to limit entries in direction order; metric queries return a matrix sampled every step.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Query parameters

  • querystringrequired
    LogQL expression
  • startstring
    Start of the range as RFC 3339 or Unix nanoseconds. Defaults to one hour before end.
  • endstring
    End of the range as RFC 3339 or Unix nanoseconds. Defaults to now.
  • sincestring
    Duration before end to use as start, such as 1h. Ignored when start is set.
  • stepstring
    Step for metric queries as a duration or float seconds.
  • limitinteger
    Maximum number of results to return.
    Minimum 0
  • directionstring
    forward or backward (default). Order in which log entries are returned.

Responses

  • 200Loki range-query responseapplication/json
    ›LokiEnvelope
    • dataobjectrequired
    • statusstringrequired
  • 400Invalid queryapplication/json
    ›ErrorEnvelope
    • errorstringrequired
Request
curl -G http://logs-reader.telemetry:3100/read/ns/default/loki/api/v1/query_range \
  -u reader:$PASSWORD \
  --data-urlencode 'query={app="checkout"} |= "error" | logfmt | duration > 250ms' \
  --data-urlencode 'start=2026-10-08T12:00:00Z' \
  --data-urlencode 'end=2026-10-08T13:00:00Z' \
  --data-urlencode 'step=60s' \
  --data-urlencode 'limit=100'
Response · 200
{
  "status": "success",
  "data": {
    "resultType": "streams",
    "result": [
      {
        "stream": {
          "app": "checkout",
          "env": "prod"
        },
        "values": [
          [
            "1791464400000000000",
            "level=error msg=\"payment declined\" duration=412ms"
          ]
        ]
      }
    ],
    "stats": {}
  }
}

Range query (form)

POST/read/ns/{namespace}/loki/api/v1/query_range
Evaluates a LogQL expression over a time range. Log queries return up to limit entries in direction order; metric queries return a matrix sampled every step.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Form fields

application/x-www-form-urlencoded
  • querystringrequired
    LogQL expression
  • startstring
    Start of the range as RFC 3339 or Unix nanoseconds. Defaults to one hour before end.
  • endstring
    End of the range as RFC 3339 or Unix nanoseconds. Defaults to now.
  • sincestring
    Duration before end to use as start, such as 1h. Ignored when start is set.
  • stepstring
    Step for metric queries as a duration or float seconds.
  • limitinteger
    Maximum number of results to return.
    Minimum 0
  • directionstring
    forward or backward (default). Order in which log entries are returned.

Responses

  • 200Loki range-query responseapplication/json
    ›LokiEnvelope
    • dataobjectrequired
    • statusstringrequired
Request
curl -X POST "http://logs-reader.telemetry:3100/read/ns/default/loki/api/v1/query_range" \
  -u reader:$PASSWORD \
  --data-urlencode 'query={app="checkout"} |= "error" | logfmt | duration > 250ms' \
  --data-urlencode 'start=2026-10-08T12:00:00Z' \
  --data-urlencode 'end=2026-10-08T13:00:00Z' \
  --data-urlencode 'step=60s' \
  --data-urlencode 'limit=100'
Response · 200
{
  "status": "success",
  "data": {
    "resultType": "streams",
    "result": [
      {
        "stream": {
          "app": "checkout",
          "env": "prod"
        },
        "values": [
          [
            "1791464400000000000",
            "level=error msg=\"payment declined\" duration=412ms"
          ]
        ]
      }
    ],
    "stats": {}
  }
}
Resource

metadata

Discovery of labels, values, and streams for query builders such as Grafana Explore.

List label values

GET/read/ns/{namespace}/loki/api/v1/label/{name}/values
Returns the sorted values of one stream label in the requested range.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.
  • namestringrequired
    Stream-label name

Query parameters

  • startstring
    Start of the range as RFC 3339 or Unix nanoseconds. Defaults to one hour before end.
  • endstring
    End of the range as RFC 3339 or Unix nanoseconds. Defaults to now.
  • sincestring
    Duration before end to use as start, such as 1h. Ignored when start is set.

Responses

  • 200Sorted values for the stream labelapplication/json
    ›LokiEnvelope
    • dataobjectrequired
    • statusstringrequired
  • 400Invalid time rangeapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 401Authentication required
Request
curl -G http://logs-reader.telemetry:3100/read/ns/default/loki/api/v1/label/app/values \
  -u reader:$PASSWORD \
  --data-urlencode 'start=2026-10-08T12:00:00Z' \
  --data-urlencode 'end=2026-10-08T13:00:00Z'
Response · 200
{
  "status": "success",
  "data": [
    "checkout",
    "gateway",
    "ledger"
  ]
}

List label names

GET/read/ns/{namespace}/loki/api/v1/labels
Returns the sorted stream-label names seen in the requested range, read from the per-segment discovery catalog.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Query parameters

  • startstring
    Range start as nanoseconds, seconds, or RFC3339
  • endstring
    Range end as nanoseconds, seconds, or RFC3339
  • sincestring
    Default lookback when start is omitted

Responses

  • 200Sorted stream-label namesapplication/json
    ›LokiEnvelope
    • dataobjectrequired
    • statusstringrequired
  • 400Invalid time rangeapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 401Authentication required
Request
curl -G http://logs-reader.telemetry:3100/read/ns/default/loki/api/v1/labels \
  -u reader:$PASSWORD \
  --data-urlencode 'start=2026-10-08T12:00:00Z' \
  --data-urlencode 'end=2026-10-08T13:00:00Z'
Response · 200
{
  "status": "success",
  "data": [
    "app",
    "env",
    "namespace"
  ]
}

Find series

GET/read/ns/{namespace}/loki/api/v1/series
Returns the label sets of streams matching at least one match[] selector. Per-entry structured metadata is intentionally excluded.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Query parameters

  • match[]array of stringrequired
    One or more Loki stream selectors
  • startstring
    Start of the range as RFC 3339 or Unix nanoseconds. Defaults to one hour before end.
  • endstring
    End of the range as RFC 3339 or Unix nanoseconds. Defaults to now.
  • sincestring
    Duration before end to use as start, such as 1h. Ignored when start is set.

Responses

  • 200Matching stream label setsapplication/json
    ›LokiEnvelope
    • dataobjectrequired
    • statusstringrequired
  • 400Invalid selector or time rangeapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 401Authentication required
Request
curl -G http://logs-reader.telemetry:3100/read/ns/default/loki/api/v1/series \
  -u reader:$PASSWORD \
  --data-urlencode 'match[]={app="checkout"}' \
  --data-urlencode 'start=2026-10-08T12:00:00Z' \
  --data-urlencode 'end=2026-10-08T13:00:00Z'
Response · 200
{
  "status": "success",
  "data": [
    {
      "app": "checkout",
      "env": "prod"
    }
  ]
}

Find series (form)

POST/read/ns/{namespace}/loki/api/v1/series
Returns the label sets of streams matching at least one match[] selector. Per-entry structured metadata is intentionally excluded.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Form fields

application/x-www-form-urlencoded
  • match[]array of stringrequired
    One or more Loki stream selectors
  • startstring
    Start of the range as RFC 3339 or Unix nanoseconds. Defaults to one hour before end.
  • endstring
    End of the range as RFC 3339 or Unix nanoseconds. Defaults to now.
  • sincestring
    Duration before end to use as start, such as 1h. Ignored when start is set.

Responses

  • 200Matching stream label setsapplication/json
    ›LokiEnvelope
    • dataobjectrequired
    • statusstringrequired
  • 400Invalid selector or time rangeapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 401Authentication required
Request
curl -X POST "http://logs-reader.telemetry:3100/read/ns/default/loki/api/v1/series" \
  -u reader:$PASSWORD \
  --data-urlencode 'match[]={app="checkout"}' \
  --data-urlencode 'start=2026-10-08T12:00:00Z' \
  --data-urlencode 'end=2026-10-08T13:00:00Z'
Response · 200
{
  "status": "success",
  "data": [
    {
      "app": "checkout",
      "env": "prod"
    }
  ]
}
Resource

ingest

Write routes, served by writers. Requests are forwarded to the owning shard over internal gRPC.

Elasticsearch handshake

GET/write/ns/{namespace}/elasticsearch
Version handshake that Elasticsearch shippers perform before sending bulk requests.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Responses

  • 200Elasticsearch version handshakeapplication/json
Request
curl http://logs-writer.telemetry:3100/write/ns/default/elasticsearch \
  -u writer:$PASSWORD
Response · 200
{}

Elasticsearch bulk

POST/write/ns/{namespace}/elasticsearch/_bulk
Elasticsearch _bulk NDJSON for Fluent Bit, Fluentd, Vector, Logstash, and Filebeat. index and create actions are ingested; update and delete fail per item because logs are append-only.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Query parameters

  • _msg_fieldstring
    Comma-separated message fields; overrides configuration
  • _time_fieldstring
    Timestamp field; overrides configuration
  • _stream_fieldsstring
    Comma-separated document fields promoted to stream labels

Request body

application/x-ndjson
Elasticsearch bulk NDJSON. index and create actions are ingested; update and delete fail per item.

Responses

  • 200Per-item bulk resultsapplication/json
    ›BulkResponse
    • errorsbooleanrequired
      True when at least one item failed.
    • itemsarray of objectrequired
      One {action: {_index, _id, status, ...}} object per bulk action, in request order.
    • tookinteger · int64required
      Minimum 0
  • 400Malformed bulk bodyapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 413Request exceeds configured limit
Request
curl -X POST "http://logs-writer.telemetry:3100/write/ns/default/elasticsearch/_bulk?_stream_fields=kubernetes.namespace%2Capp" \
  -u writer:$PASSWORD \
  -H 'Content-Type: application/x-ndjson' \
  --data-binary $'{"index":{"_index":"logstash-2026.10.08"}}\n{"@timestamp":"2026-10-08T13:00:00Z","message":"payment declined","app":"checkout"}\n'
Response · 200
{
  "took": 3,
  "errors": false,
  "items": [
    {
      "index": {
        "_index": "logstash",
        "_id": "1",
        "status": 201
      }
    }
  ]
}

Elasticsearch health

GET/write/ns/{namespace}/elasticsearch/_cluster/health
Health handshake for shippers that check cluster health. Always reports green.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Responses

  • 200Always greenapplication/json
Request
curl http://logs-writer.telemetry:3100/write/ns/default/elasticsearch/_cluster/health \
  -u writer:$PASSWORD
Response · 200
{}

Elasticsearch bulk (index)

POST/write/ns/{namespace}/elasticsearch/{index}/_bulk
Same as _bulk, with a default index for actions that omit _index.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.
  • indexstringrequired
    Default index for actions without _index

Query parameters

  • _msg_fieldstring
    Document field to use as the log line for this request.
  • _time_fieldstring
    Document field holding the entry timestamp for this request.
  • _stream_fieldsstring
    Comma-separated document fields to promote to stream labels for this request.

Request body

application/x-ndjson

Responses

  • 200Per-item bulk resultsapplication/json
    ›BulkResponse
    • errorsbooleanrequired
      True when at least one item failed.
    • itemsarray of objectrequired
      One {action: {_index, _id, status, ...}} object per bulk action, in request order.
    • tookinteger · int64required
      Minimum 0
  • 400Malformed bulk bodyapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 413Request exceeds configured limit
Request
curl -X POST "http://logs-writer.telemetry:3100/write/ns/default/elasticsearch/logstash-2026.10.08/_bulk?_stream_fields=kubernetes.namespace%2Capp" \
  -u writer:$PASSWORD \
  -H 'Content-Type: application/x-ndjson' \
  --data-binary $'{"create":{}}\n{"@timestamp":"2026-10-08T13:00:00Z","message":"payment declined","app":"checkout"}\n'
Response · 200
{
  "errors": false,
  "items": [
    {}
  ],
  "took": 0
}

Push logs

POST/write/ns/{namespace}/loki/api/v1/push
Loki push API. Accepts application/json or Snappy-compressed application/x-protobuf. Point Promtail, Grafana Alloy, or any Loki client at this route.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Request body

application/jsonapplication/x-protobuf
Loki push JSON or Snappy-compressed protobuf.
  • streamsarray of LokiStreamrequired
    ›Show child attributes
    • streammap of stringrequired
      Stream labels.
    • valuesarray of array of objectrequired
      Loki [timestamp_ns, line, optional_metadata] tuples.

Responses

  • 204Logs accepted
  • 400Invalid push requestapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 413Request exceeds configured limit
Request
curl -X POST "http://logs-writer.telemetry:3100/write/ns/default/loki/api/v1/push" \
  -u writer:$PASSWORD \
  -H 'Content-Type: application/json' \
  --data-binary @- <<'EOF'
{
  "streams": [
    {
      "stream": {
        "app": "checkout",
        "env": "prod"
      },
      "values": [
        [
          "1791464400000000000",
          "level=error msg=\"payment declined\" duration=412ms",
          {
            "trace_id": "4bf92f3577b34da6a3ce929d0e0e4736"
          }
        ]
      ]
    }
  ]
}
EOF

OTLP logs

POST/write/ns/{namespace}/otlp/v1/logs
OTLP/HTTP ExportLogsServiceRequest, protobuf or JSON by Content-Type. Resource attributes become stream labels per the OTLP mapping; the rest is structured metadata.

Path parameters

  • namespacestringrequired
    Tenant namespace. A NamespaceAuthentication for this database must grant the caller access to it.

Request body

application/jsonapplication/x-protobuf
OTLP ExportLogsServiceRequest.

Responses

  • 200OTLP logs accepted
  • 400Invalid OTLP requestapplication/json
    ›ErrorEnvelope
    • errorstringrequired
  • 413Request exceeds configured limit
Request
curl -X POST "http://logs-writer.telemetry:3100/write/ns/default/otlp/v1/logs" \
  -u writer:$PASSWORD \
  -H 'Content-Type: application/json' \
  --data-binary @- <<'EOF'
{
  "resourceLogs": [
    {
      "resource": {
        "attributes": [
          {
            "key": "service.name",
            "value": {
              "stringValue": "checkout"
            }
          }
        ]
      },
      "scopeLogs": [
        {
          "logRecords": [
            {
              "timeUnixNano": "1791464400000000000",
              "severityText": "ERROR",
              "body": {
                "stringValue": "payment declined"
              }
            }
          ]
        }
      ]
    }
  ]
}
EOF
Resource

operations

Probes for Kubernetes and load balancers.

Liveness

GET/-/healthy
Returns 200 while the process is running. Use it as the Kubernetes liveness probe; it is unprefixed and not namespace-scoped.

Responses

  • 200Process is healthy
Request
curl http://logs-reader.telemetry:3100/-/healthy

Readiness

GET/-/ready
Returns 200 once every storage shard assigned to this pod is open, and 503 while shards are still being acquired or handed off. Use it as the readiness probe.

Responses

  • 200Server is ready
  • 503Assigned shards are not ready
Request
curl http://logs-reader.telemetry:3100/-/ready