# Via HTTP

Enable ISO GQL on a SurrealDB instance and run queries through POST /gql.

_(since v3.2.0)_

The **`POST /gql`** endpoint accepts a **raw GQL query** in the request body (not JSON-wrapped). Authentication and namespace selection use the same headers as [`POST /sql`](/docs/reference/rest-api/http-protocol.md). For the full HTTP reference (headers, response envelope, limits), see [`POST /gql`](/docs/reference/rest-api/http-protocol.md#gql).

## Start SurrealDB with GQL

From **3.3.0**, start a normal instance - ISO GQL is on by default:

```bash
surreal start --log info --user root --pass secret memory
```

On **3.2.x**, pass the experimental capability (storage path after the flag, or use `memory`):

```bash
surreal start --log info --user root --pass secret \
  --allow-experimental gql memory
```

```bash
export SURREAL_CAPS_ALLOW_EXPERIMENTAL=gql
surreal start --log info --user root --pass secret memory
```

> [!NOTE]
> This is **not** [GraphQL](/docs/learn/querying/graphql/overview.md) - use [`POST /graphql`](/docs/reference/rest-api/http-protocol.md#graphql) for GraphQL queries.
## Load sample data

Use [`POST /sql`](/docs/reference/rest-api/http-protocol.md) with namespace **`main`** and database **`main`** (set via headers below):

```bash
curl -sS -X POST -u "root:secret" \
  -H "Surreal-NS: main" -H "Surreal-DB: main" \
  -H "Accept: application/json" -H "Content-Type: text/plain" \
  -d "CREATE person:1 SET name = 'A', age = 30, active = true, city = 'London';
CREATE person:2 SET name = 'B', age = 20, active = false, city = 'Paris';
CREATE person:3 SET name = 'C', city = 'London';
CREATE city:1 SET name = 'London';
INSERT RELATION INTO knows [
	{ id: knows:k12, in: person:1, out: person:2, since: 2021 },
	{ id: knows:k21, in: person:2, out: person:1, since: 2018 },
	{ id: knows:k23, in: person:2, out: person:3, since: 2020 },
	{ id: knows:k1c, in: person:1, out: city:1, since: 2019 },
	{ id: knows:k31, in: person:3, out: person:1 }
];" \
  http://localhost:8000/sql
```

## `POST /gql`

Send the GQL query as the **raw body** with `Content-Type: text/plain` (or omit; UTF-8 text is expected).

```bash
curl -sS -X POST -u "root:secret" \
  -H "Surreal-NS: main" -H "Surreal-DB: main" \
  -H "Accept: application/json" -H "Content-Type: text/plain" \
  -d 'MATCH (n:person) RETURN n.name AS name ORDER BY name' \
  http://localhost:8000/gql
```

Example response (same envelope as `/sql`):

```json
[
	{
		"status": "OK",
		"result": [
			{ "name": "A" },
			{ "name": "B" },
			{ "name": "C" }
		],
		"time": "1.5ms"
	}
]
```

### Response formats

Set `Accept` to:

- `application/json` (default)
- `application/cbor` for CBOR-encoded results

Parse errors return **HTTP 400** with an error payload.

## Mutations

The same endpoint accepts **data-modifying** GQL - `INSERT`, `SET`, `REMOVE`, and `DELETE` - interleaved with `MATCH` / `OPTIONAL` in one query. Mutation-bearing requests run in a **write transaction** and enforce the same permissions as SurrealQL writes.

Example - update a property and return the new value:

```bash
curl -sS -X POST -u "root:secret" \
  -H "Surreal-NS: main" -H "Surreal-DB: main" \
  -H "Accept: application/json" -H "Content-Type: text/plain" \
  -d "MATCH (n:person WHERE n.name = 'A') SET n.age = 99 RETURN n.age AS age" \
  http://localhost:8000/gql
```

See [GQL mutations](/docs/learn/querying/gql/mutations.md) for `INSERT`, `REMOVE`, `DELETE`, read-after-write interleaving, and rejected forms.

## WebSocket RPC

On an authenticated WebSocket session, send the query as the first parameter. Pass **typed** variables as an optional second object:

```json
{
	"id": 1,
	"method": "gql",
	"params": [
		"MATCH (n:person) RETURN n.name AS name ORDER BY name"
	]
}
```

With parameters:

```json
{
	"id": 2,
	"method": "gql",
	"params": [
		"MATCH (n:person) WHERE n.age > $min RETURN n.name AS name",
		{ "min": 18 }
	]
}
```

## Try without HTTP - `eval::gql`

If you prefer the CLI or SurrealDB Studio over cURL, run GQL through [`eval::gql`](/docs/reference/query-language/functions/database-functions/eval.md#evalgql) inside SurrealQL. You still need [`--allow-eval-query`](/docs/learn/security/authorization/capabilities.md#eval-queries), as `eval::*` is denied by default even under `--allow-all`. From 3.3.0 you do not need `--allow-experimental gql` as well (required on 3.2.x only).

One process (embedded): pass `--allow-eval-query` on `surreal sql`, load the [seed data](#load-sample-data) with ordinary SurrealQL, then:

```surql
eval::gql("MATCH (n:person) RETURN n.name AS name ORDER BY name");
```

```bash
surreal sql --user root --pass secret --allow-eval-query
```

**Two processes (remote):** enable eval on **`surreal start`**, then connect with `surreal sql` as usual - capability flags on the client do not turn on `eval` for a remote engine.

```bash
surreal start --user root --pass secret --allow-eval-query
```

Mutations work the same way: `eval::gql("MATCH (n:person WHERE n.name = 'A') SET n.age = 99 RETURN n.age AS age")` runs in the open SurrealQL transaction. See [GQL mutations](/docs/learn/querying/gql/mutations.md) and [Eval functions](/docs/reference/query-language/functions/database-functions/eval.md#evalgql).
