﻿---
title: PromQL HTTP API
description: Prometheus-compatible HTTP endpoints for PromQL queries and metric discovery against time series data in Elasticsearch.
url: https://www.elastic.co/elastic/docs-builder/docs/3409/reference/query-languages/promql/promql-http-api
products:
  - Elasticsearch
applies_to:
  - Elastic Cloud Serverless: Preview
  - Elastic Stack: Preview since 9.4
---

# PromQL HTTP API
<warning>
  This functionality is in technical preview and might be changed or removed in a future release.
  Elastic will work to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.
</warning>

These endpoints run under the `/_prometheus/` prefix.
They are intended for Prometheus-compatible tooling such as Grafana data sources, autocompletion, variable queries, and similar clients.
These APIs only consider metric data stored in [time series data streams](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3409/manage-data/data-store/data-streams/time-series-data-stream-tsds) (TSDS).

## Index scoping

Every path has two forms:
- Cluster default: `/_prometheus/api/v1/<path>`
- Explicit index expression: `/_prometheus/{index}/api/v1/<path>`

The `{index}` segment is an Elasticsearch index expression (for example, `metrics-generic.prometheus-*`) that restricts which indices are considered in the query.
This can reduce latency on clusters that contain many large time series data streams when you query a subset of indices.
When you omit `{index}` in the path, qualifying indices are identified through the default index expression `metrics-*`.

## Query endpoints

These endpoints mirror the Prometheus [range query](https://prometheus.io/docs/prometheus/latest/querying/api/#range-queries) and [instant query](https://prometheus.io/docs/prometheus/latest/querying/api/#instant-queries) APIs.

### Range query

`GET  /_prometheus/api/v1/query_range`

`POST /_prometheus/api/v1/query_range`

`GET  /_prometheus/{index}/api/v1/query_range`

`POST /_prometheus/{index}/api/v1/query_range`
This endpoint evaluates a PromQL expression over a time window and returns matrix data (`resultType: "matrix"`).

| Parameter | Required          | Description                                                           |
|-----------|-------------------|-----------------------------------------------------------------------|
| `query`   | Yes               | PromQL expression                                                     |
| `start`   | Yes               | Range start, [Timestamp](#promql-http-api-param-timestamp)            |
| `end`     | Yes               | Range end, [Timestamp](#promql-http-api-param-timestamp)              |
| `step`    | Yes               | Resolution between samples, [Step width](#promql-http-api-param-step) |
| `limit`   | No (default: `0`) | Maximum number of series returned, [`limit`](#promql-http-api-limit)  |

The `timeout`, `lookback_delta`, and `stats` parameters are not supported yet (see [Limitations](/elastic/docs-builder/docs/3409/reference/query-languages/promql/promql-limitations#promql-limitations-unsupported-query-params)).

### Instant query

`GET  /_prometheus/api/v1/query`

`POST /_prometheus/api/v1/query`

`GET  /_prometheus/{index}/api/v1/query`

`POST /_prometheus/{index}/api/v1/query`
This endpoint evaluates at a single instant and returns vector data (`resultType: "vector"`).

| Parameter | Required          | Description                                                                                                                                                                                                                                                                |
|-----------|-------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `query`   | Yes               | PromQL expression                                                                                                                                                                                                                                                          |
| `time`    | No (default: now) | Evaluation instant, [Timestamp](#promql-http-api-param-timestamp). The handler still uses an internal five-minute range ending at this time (see [Limitations](https://www.elastic.co/elastic/docs-builder/docs/3409/reference/query-languages/promql/promql-limitations)) |
| `limit`   | No (default: `0`) | Maximum number of series returned, [`limit`](#promql-http-api-limit)                                                                                                                                                                                                       |

The `timeout`, `lookback_delta`, and `stats` parameters are not supported yet (see [Limitations](/elastic/docs-builder/docs/3409/reference/query-languages/promql/promql-limitations#promql-limitations-unsupported-query-params)).

## Metadata and discovery endpoints

These entrypoints mirror the Prometheus [metric metadata](https://prometheus.io/docs/prometheus/latest/querying/api/#querying-metric-metadata), [label-name discovery](https://prometheus.io/docs/prometheus/latest/querying/api/#getting-label-names), [label-value queries](https://prometheus.io/docs/prometheus/latest/querying/api/#querying-label-values), and [series discovery by matchers](https://prometheus.io/docs/prometheus/latest/querying/api/#finding-series-by-label-matchers) APIs so UIs can browse metrics, build [time series selectors](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors), and populate template variables.

### Label names

`GET  /_prometheus/api/v1/labels`

`POST /_prometheus/api/v1/labels`

`GET  /_prometheus/{index}/api/v1/labels`

`POST /_prometheus/{index}/api/v1/labels`
This endpoint returns sorted label names present on matching series.
`match[]` is not required. If you omit every `match[]`, results are still limited to the `start` and `end` time range.

| Parameter | Required                       | Description                                                                                                                                                                            |
|-----------|--------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `match[]` | No (default: no selectors)     | Optional repeated [selectors](#promql-http-api-param-match) (for example, `match[]=up{job="prometheus"}`). Omit all to return label names for every series in the selected time window |
| `start`   | No (default: 24h before `end`) | Start of time range, [Timestamp](#promql-http-api-param-timestamp)                                                                                                                     |
| `end`     | No (default: now)              | End of time range, [Timestamp](#promql-http-api-param-timestamp)                                                                                                                       |
| `limit`   | No (default: `0`)              | Maximum number of label names in the response, [`limit`](#promql-http-api-limit)                                                                                                       |


### Label values

`GET /_prometheus/api/v1/label/{name}/values`

`GET /_prometheus/{index}/api/v1/label/{name}/values`
This endpoint returns sorted, deduplicated values for one label.
`match[]` is not required. If you omit every `match[]`, results are still limited to the `start` and `end` time range.
Label names can use OpenMetrics `U__` encoding for characters that are not valid in Prometheus label names. The server decodes them before matching series.

| Parameter | Required                       | Description                                                                                                        |
|-----------|--------------------------------|--------------------------------------------------------------------------------------------------------------------|
| `match[]` | No (default: no selectors)     | Optional repeated [selectors](#promql-http-api-param-match). Same semantics as [`labels`](#promql-http-api-labels) |
| `start`   | No (default: 24h before `end`) | Start of time range, [Timestamp](#promql-http-api-param-timestamp)                                                 |
| `end`     | No (default: now)              | End of time range, [Timestamp](#promql-http-api-param-timestamp)                                                   |
| `limit`   | No (default: `0`)              | Maximum number of values returned for this label, [`limit`](#promql-http-api-limit)                                |

Unknown label names are returned as an empty successful result (`data: []`), matching typical Prometheus client expectations.

### Series

`GET  /_prometheus/api/v1/series`

`POST /_prometheus/api/v1/series`

`GET  /_prometheus/{index}/api/v1/series`

`POST /_prometheus/{index}/api/v1/series`
This endpoint returns the set of series matching the given selectors.
At least one `match[]` parameter is required.

| Parameter | Required                       | Description                                                                 |
|-----------|--------------------------------|-----------------------------------------------------------------------------|
| `match[]` | Yes (at least one)             | Repeated [selectors](#promql-http-api-param-match)                          |
| `start`   | No (default: 24h before `end`) | Start of time range, [Timestamp](#promql-http-api-param-timestamp)          |
| `end`     | No (default: now)              | End of time range, [Timestamp](#promql-http-api-param-timestamp)            |
| `limit`   | No (default: `0`)              | Maximum number of series in the response, [`limit`](#promql-http-api-limit) |


### Metric metadata

<applies-to>Elastic Stack: Planned</applies-to> <applies-to>Elastic Cloud Serverless: Preview</applies-to>
`GET /_prometheus/api/v1/metadata`

`GET /_prometheus/{index}/api/v1/metadata`
This endpoint returns metric-level information such as type, help, and unit, analogous to Prometheus `TYPE`, `HELP`, and `UNIT` lines.
The `help` field is always an empty string for now (see [Limitations](/elastic/docs-builder/docs/3409/reference/query-languages/promql/promql-limitations#promql-limitations-metadata-help)).

| Parameter          | Required                              | Description                                                                               |
|--------------------|---------------------------------------|-------------------------------------------------------------------------------------------|
| `metric`           | No (default: all metrics in lookback) | Restrict to a single metric name                                                          |
| `limit`            | No (default: `0`)                     | Maximum number of distinct metrics in the response, [`limit`](#promql-http-api-limit)     |
| `limit_per_metric` | No (default: `0`)                     | Maximum number of metadata entries returned per metric, [`limit`](#promql-http-api-limit) |

The `metadata` route does not support `match[]`, `start`, or `end`.
Elasticsearch discovers type and unit using the ES|QL [`METRICS_INFO`](https://www.elastic.co/elastic/docs-builder/docs/3409/reference/query-languages/esql/commands/metrics-info) command over [time series data streams](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3409/manage-data/data-store/data-streams/time-series-data-stream-tsds) (TSDS), with a fixed 24-hour lookback ending when the request runs.

## Request parameter formats

Parameter encodings match the [Prometheus HTTP API](https://prometheus.io/docs/prometheus/latest/querying/api/). See the upstream [format overview](https://prometheus.io/docs/prometheus/latest/querying/api/#format-overview).
For `GET` requests, send parameters in the query string.
For endpoints that support `POST`, send parameters in an `application/x-www-form-urlencoded` request body.
Do not repeat a parameter in both the URL and the form body.
<note>
  Form-encoded `POST` requests are accepted only when [security](https://www.elastic.co/elastic/docs-builder/docs/3409/reference/elasticsearch/configuration-reference/security-settings) is enabled, [`xpack.security.http.ssl.enabled`](https://www.elastic.co/elastic/docs-builder/docs/3409/reference/elasticsearch/configuration-reference/security-settings) is `true` on the Elasticsearch HTTP interface, and the request is authenticated (not anonymous). The check uses Elasticsearch’s own HTTP TLS setting, so deployments that terminate TLS before Elasticsearch and expose plain HTTP to the node must use `GET` with query-string parameters instead. Unauthenticated or plain-HTTP `POST` requests with `application/x-www-form-urlencoded` bodies return HTTP `406 Not Acceptable`.
</note>


### Timestamps

Values may be an [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) timestamp or Unix time in seconds as a numeric string, with optional fractional digits for sub-second precision. This matches Prometheus request parsing. Sample timestamps inside JSON results use Unix seconds, as in Prometheus.

### Selectors (`match[]`)

Each value must be URL-encoded. Syntax is the same as Prometheus [time series selectors](https://prometheus.io/docs/prometheus/latest/querying/basics/#time-series-selectors) (for example, `up` or `http_requests_total{job="api"}`).
Repeatable query parameters use a `[]` suffix, matching Prometheus. Whether any `match[]` must be present is defined in each endpoint’s parameter table.

### Step

The `step` query parameter accepts:
- A non-negative decimal integer string: seconds between samples (for example, `15` for 15s resolution).
- Or Prometheus-style duration literals such as `30s`, `5m`, or `1h30m`: a non-negative integer plus a unit suffix (`ms`, `s`, `m`, `h`, `d`, `w`, or `y`), repeated and concatenated when needed (for example, `1h30m`). See Prometheus [float literals and time durations](https://prometheus.io/docs/prometheus/latest/querying/basics/#float-literals-and-time-durations).


### `limit`

`limit` defaults to `0`, which means no cap from the request (Prometheus-style unlimited) on routes that accept it. Elasticsearch may still truncate very large responses when enforcing [`esql.query.timeseries_result_truncation_max_size`](/elastic/docs-builder/docs/3409/reference/query-languages/esql/limitations#esql-max-rows).
The [metadata](#promql-http-api-metadata-endpoint) route also takes `limit_per_metric` with the same `0` default (no per-metric cap from the request).

## Response format

Responses use JSON. Successful calls return HTTP 200 with:
```json
{
  "status": "success",
  "data": { ... }
}
```

The `data` object shape depends on the route (for example, `resultType` and `result` for `query` / `query_range`).
When the `limit` is reached and the server detects truncation, the response might include a top-level `warnings` array (strings). The preview uses a fixed message such as `results truncated due to limit`.
Numeric sample values in query results are JSON strings (including `NaN`, `+Inf`, and `-Inf`), matching common Prometheus JSON encoding.
Errors return a non-2xx HTTP status and a JSON body of the form:
```json
{
  "status": "error",
  "errorType": "bad_data",
  "error": "<message>"
}
```

Client errors (HTTP 4xx) mean the request or expression is not valid for this implementation, for example, malformed parameters, parameters not supported yet on a route, invalid selectors, or PromQL that Elasticsearch does not evaluate yet (see [Limitations](https://www.elastic.co/elastic/docs-builder/docs/3409/reference/query-languages/promql/promql-limitations)). Those failures usually return `errorType: bad_data`.
Server errors (HTTP 5xx) and timeout responses reflect operational failures inside Elasticsearch. Those responses typically use `errorType: timeout` or `execution` depending on the situation.

## Further reading

- [Prometheus query API](https://prometheus.io/docs/prometheus/latest/querying/api/)
- [Prometheus remote write](https://docs-v3-preview.elastic.dev/elastic/docs-builder/docs/3409/manage-data/data-store/data-streams/tsds-ingest-prometheus-remote-write)
- [`PROMQL` command (ES|QL)](https://www.elastic.co/elastic/docs-builder/docs/3409/reference/query-languages/esql/commands/promql)
- [Limitations](https://www.elastic.co/elastic/docs-builder/docs/3409/reference/query-languages/promql/promql-limitations)