# run-eventql-query

Runs an **EventQL query** and sends its **results**.

- **Route:** `QUERY /api/v2/data/run-eventql-query`
- **Category:** `data`
- **Authentication:** required, with the API token
- **Answer:** a stream of NDJSON

**[EventQL](/docs/eventsourcingdb/eventql)** filters, sorts, groups, and projects the events, across all subjects, into **results of any shape** you like. A query **sees one state of the database** throughout: the events up to the latest one at the moment it starts, so events written while it runs are not part of it. The tutorial **[Running EventQL Queries](/learn/tutorials/first-steps-with-eventsourcingdb/running-eventql-queries)** walks through it step by step.

## Request

The body is a JSON object, with the content type `application/json`:

| Field | Type | Required | Meaning |
| --- | --- | --- | --- |
| `query` | string | yes | The EventQL query to run, such as `FROM e IN events PROJECT INTO e`. |

To list the ID and the type of every event of `/books/42`:

```shell
curl \
  -X QUERY \
  -H "authorization: Bearer secret" \
  -H "content-type: application/json" \
  -d '{"query":"FROM e IN events WHERE e.subject == \"/books/42\" PROJECT INTO { id: e.id, type: e.type }"}' \
  http://localhost:3000/api/v2/data/run-eventql-query
```

## Answer

The answer is a **stream of items**, one per line. Each result is a `row` item:

| Type | Data | When |
| --- | --- | --- |
| `row` | `value`, the result as the `PROJECT INTO` clause of the query shapes it: any JSON value, `null` included, or an array for each group of a `GROUP BY` | For every result of the query. |
| `error` | `code`, `description`, and `details` | When the query cannot be run, or fails while it runs, see **[Errors](#errors)**. |
| `heartbeat` | empty | While nothing else is sent for a while, to keep the connection alive. |
| `end` | empty | Once, as the last item, when the stream ends cleanly. |

**Heartbeats and the `end` item** work as on every stream of the API, see **[Streams](/docs/eventsourcingdb/api#streams)**. A query that finds nothing is answered with the `end` item alone. An error can **follow rows that were sent already**, for example when the query divides by zero for one of its events; the rows before it are then only part of the result. A query **ends once its client goes away**, also while it combines several sources, sorts, groups, or computes `STDDEV` or `VARIANCE` in memory, so that it does not go on computing for nobody.

For a database in which `/books/42` holds a `book-acquired`, a `book-borrowed`, and a `book-returned` event, the request above is answered with:

```json
{"type":"row","data":{"value":{"id":"0","type":"io.eventsourcingdb.library.book-acquired"}}}
{"type":"row","data":{"value":{"id":"1","type":"io.eventsourcingdb.library.book-borrowed"}}}
{"type":"row","data":{"value":{"id":"2","type":"io.eventsourcingdb.library.book-returned"}}}
{"type":"end","data":{}}
```

## Errors

The query reports these errors as an `error` item, followed by the `end` item:

- **[`query-missing`](/docs/eventsourcingdb/errors/query-missing)**: The request leaves out the query, or sends an empty string.
- **[`query-malformed`](/docs/eventsourcingdb/errors/query-malformed)**: The query does not parse, which includes a query of nothing but whitespace.
- **[`query-too-deep`](/docs/eventsourcingdb/errors/query-too-deep)**: The query nests more than 256 levels, or holds a chain of more than 10,000 operands. This is checked before the query is parsed, so it holds for a query that does not parse as well.
- **[`query-unevaluable`](/docs/eventsourcingdb/errors/query-unevaluable)**: The query parses, but fails while it runs, such as on a division by zero, possibly after it has sent rows.
- **[`indexes-rebuilding`](/docs/eventsourcingdb/errors/indexes-rebuilding)**: The indexes are still being rebuilt after an upgrade, which refuses every query before its results begin.
- **[`restore-in-progress`](/docs/eventsourcingdb/errors/restore-in-progress)**: A restore is running, which refuses queries until it has finished.
- **[`file-unreadable`](/docs/eventsourcingdb/errors/file-unreadable)**: A file of the store that the query needs is damaged, such as an events file whose checksum no longer matches.
- **[`store-failed`](/docs/eventsourcingdb/errors/store-failed)**: The store refuses reads for good, after a restore that could not empty it again.
- **[`server-shutting-down`](/docs/eventsourcingdb/errors/server-shutting-down)**: The server began to shut down while the query was running. Before the stream begins, the server answers with `503` instead.

## Status Codes

Before the stream begins, the server answers with a status code other than `200` where it cannot take the request at all, as described in **[Errors](/docs/eventsourcingdb/api#errors)**:

- **`400`**: The content type of the body is not `application/json`, or the body is no JSON object of the shape above, for example with a field the route does not know, such as `options`, with a query that is no string, or with `null` as a value.
- **`401`**: The API token is missing or wrong.
- **`408`**: The body did not arrive in time.
- **`413`**: The body is larger than its **[limit](/docs/eventsourcingdb/limits)**.
- **`429`**: Too many requests were sent, or the client already holds 256 open streams, see **[Rate Limiting](/docs/eventsourcingdb/rate-limiting)**; the answer says when to try again.
- **`500`**: The server failed unexpectedly before the stream began. Once it has begun, the stream breaks off without its `end` item instead.
- **`503`**: The server is shutting down.
