Source: https://dinakar-rewind.docs.pageloop.ai/api-reference/query/runquery

# Run a read-only SQL query

POST `https://api.rewind.rest/v1/query`

Executes a single read-only SELECT (or WITH … SELECT) statement against the Rewind database and returns column names plus array-of-array row tuples. Gated server-side: writes, DDL, multi-statement input, and access to secret tables are rejected. A LIMIT is enforced automatically (200 default, 500 max). Fetch GET /v1/schema first for the annotated table list.

## Authorization

#### Authorization (header, string, required)

API key. Read keys (rw\_live\_...) access GET endpoints. Admin keys (rw\_admin\_...) access all endpoints.

## Body

#### sql (body, string, required)

A single read-only SELECT (or WITH … SELECT) statement. A LIMIT is applied automatically (200 default, 500 max).

## Response

#### 200

Query results as column names plus row tuples

#### columns (array of string, required)

#### rows (array of array of object, required)

#### row\_count (integer, required)

#### truncated (boolean, required)

True when rows were dropped to fit the response ceiling.

#### integration (string, required)

The single upstream service the queried tables belong to (lastfm, strava, discogs, …), or null when the query spans several or reads only shared tables. Renderers use it to tint a single-series chart in that service’s colour.

#### 400

Bad request

#### error (string, required)

#### status (integer, required)

#### 401

Unauthorized

#### error (string, required)

#### status (integer, required)

#### Request

```bash cURL
curl -X POST 'https://api.rewind.rest/v1/query' \
  -H 'Authorization: Bearer <token>' \
  -H 'Content-Type: application/json' \
  -d '{"sql": "SELECT strftime('%Y', scrobbled_at) AS year, count(*) AS plays FROM lastfm_scrobbles GROUP BY year ORDER BY year"}'
```

```javascript JavaScript
const res = await fetch('https://api.rewind.rest/v1/query', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer <token>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({"sql": "SELECT strftime('%Y', scrobbled_at) AS year, count(*) AS plays FROM lastfm_scrobbles GROUP BY year ORDER BY year"}),
});
const data = await res.json();
```

```python Python
import requests

res = requests.post(
    'https://api.rewind.rest/v1/query',
    headers={'Authorization': 'Bearer <token>'},
    json={"sql": "SELECT strftime('%Y', scrobbled_at) AS year, count(*) AS plays FROM lastfm_scrobbles GROUP BY year ORDER BY year"}
)
data = res.json()
```

#### Response

```json 200
{
  "columns": [
    "year",
    "plays"
  ],
  "rows": [
    [
      "2024",
      18234
    ],
    [
      "2025",
      21012
    ]
  ],
  "row_count": 2,
  "truncated": false,
  "integration": "lastfm"
}
```

```json 400
{
  "error": "Not found",
  "status": 404
}
```

```json 401
{
  "error": "Not found",
  "status": 404
}
```
