> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreflux.org/llms.txt
> Use this file to discover all available pages before exploring further.

# QuestDB

> Client-mode REST API connector for QuestDB: ILP over HTTP writes, SQL queries via /exec, CSV export via /exp, and /ping health

Technical Preview

## Overview

A client-mode connector for the [QuestDB HTTP REST API](https://questdb.com/docs/reference/api/rest/) that streams MQTT telemetry into QuestDB tables and runs SQL from MQTT:

| Catalog connector event | Endpoint | Notes |
| - | - | - |
| POST write (ILP) | `POST /write?precision=` | [ILP over HTTP](https://questdb.com/docs/reference/api/ilp/overview/), `text/plain` line protocol body, `204` on success. Tables and columns auto-create. |
| GET exec | `GET /exec?query=` | SQL (SELECT, INSERT, CREATE TABLE) returning JSON `columns` + `dataset` |
| GET exp | `GET /exp?query=` | SQL result as CSV |
| GET ping | `GET /ping` | Health check, `204` |

Default `BASE_ADDRESS` is `http://YOUR_QUESTDB_HOST:9000` (QuestDB's HTTP port). Topics use `data/questdb/<object>/<verb>`.

> [!NOTE]
>
> **CSV import (`/imp`) is not a client event.** QuestDB only accepts `multipart/form-data` uploads on `/imp`; a raw body returns `400 Non-multipart POST not supported`. Use ILP `/write` for streaming rows, or `/exec` with `INSERT INTO …` for small batches.

## Auth

QuestDB open source has no HTTP auth by default. When you enable `http.user` / `http.password` (OSS) or RBAC (QuestDB Enterprise), pass the full header value in `authorization`, such as `Basic base64(user:pass)` or `Bearer <REST token>`. Send an empty string when the server has no auth. Keep the value in a Hub secret such as `QUESTDB_AUTH` and never commit it.

## Basic Syntax

```lot wrap theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
DEFINE ROUTE QuestdbRestApi WITH TYPE REST_API
    ADD REST_API_CONFIG
        WITH BASE_ADDRESS "http://YOUR_QUESTDB_HOST:9000"
        WITH ENABLE_CLIENT "true"
        WITH USE_SSL "false"
        WITH REQUEST_TIMEOUT '60'
        WITH DEFAULT_CONTENT_TYPE "application/json"
    ADD EVENT Ping
        WITH SOURCE_TOPIC "data/questdb/ping"
        WITH DESTINATION_TOPIC "data/questdb/ping/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/ping"
        WITH HEADERS
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT ExecQuery
        WITH SOURCE_TOPIC "data/questdb/query/exec"
        WITH DESTINATION_TOPIC "data/questdb/query/exec/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/exec?query={value.json.query}&count=true"
        WITH HEADERS
            ADD "Accept" "application/json"
            ADD "Authorization" "{value.json.authorization}"
    ADD EVENT WriteIlp
        WITH SOURCE_TOPIC "data/questdb/ilp/write"
        WITH DESTINATION_TOPIC "data/questdb/ilp/write/response"
        WITH METHOD "POST"
        WITH ENDPOINT "/write?precision={value.json.precision}"
        WITH HEADERS
            ADD "Content-Type" "text/plain; charset=utf-8"
            ADD "Authorization" "{value.json.authorization}"
        WITH BODY "{payload}"
    ADD EVENT ExportCsv
        WITH SOURCE_TOPIC "data/questdb/query/export"
        WITH DESTINATION_TOPIC "data/questdb/query/export/response"
        WITH METHOD "GET"
        WITH ENDPOINT "/exp?query={value.json.query}"
        WITH HEADERS
            ADD "Accept" "text/csv"
            ADD "Authorization" "{value.json.authorization}"
```

## Example MQTT payloads

**Write telemetry (topic `data/questdb/ilp/write`).** JSON fields fill the query placeholders; the body is line protocol:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{ "authorization": "", "precision": "ms" }
```

```text theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
factory_smoke,site=porto value=21.5 1791234567890
```

**SQL query (topic `data/questdb/query/exec`).** URL-encode the SQL before publishing:

```json theme={"theme":"css-variables","languages":{"custom":["/languages/lot.json"]}}
{ "authorization": "", "query": "SELECT%20site,value%20FROM%20factory_smoke%20LIMIT%2010" }
```

The response topic receives QuestDB's JSON, for example `{"columns":[…],"dataset":[["porto",21.5]],"count":1}`.

**CSV export (topic `data/questdb/query/export`)** takes the same payload as `exec`. **Health (topic `data/questdb/ping`)** takes `{ "authorization": "" }`.

## Testing

The factory smoke ran against a local QuestDB 10.0.1 instance: `GET /ping` returned 204, `CREATE TABLE` through `/exec` returned 200, an ILP `POST /write?precision=ms` returned 204, and the row came back through `/exec` (200 JSON) and `/exp` (200 CSV).

## Related

* [REST API Connectors](/latest/lot-language/routes/rest-api-routes)
* [REST API Apps](/latest/lot-language/routes/rest-api-apps/index)
* [InfluxDB](/latest/lot-language/routes/rest-api-apps/influxdb)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.