Documentation
REST API
Create, query and manage DuckHouse databases over HTTP with an API key: run SQL, read schemas and set up Connections.
Everything the dashboard does is available over HTTPS: create and delete databases, run SQL, read schemas, and manage Connections. Requests and responses are JSON.
| Base URL | https://duckhouse.co/api/v1 |
| Authentication | Authorization: Bearer dhk_…, an API key |
| Content type | application/json |
export DUCKHOUSE_API_KEY=dhk_your_key
curl https://duckhouse.co/api/v1/databases \
-H "Authorization: Bearer $DUCKHOUSE_API_KEY"Errors
Failures return a matching HTTP status and a body of the form { "error": "what went wrong" }.
| Status | Meaning |
|---|---|
| 400 | The request is malformed, or the SQL failed. The message says which. |
| 401 | The API key is missing, wrong, expired or revoked. |
| 403 | The key is valid but not allowed to do this, for example a write with a read-scoped key. |
| 404 | No such database or Connection in your organization. |
| 409 | The database is not in a state that allows this, for example it is still provisioning. |
Databases
List your organization’s databases, newest first.
Create a database. Requires a full-scope key.
| Field | Type | Default | |
|---|---|---|---|
name | string | required | 1 to 50 characters. |
region | string | iad | iad, lax, fra or sin. DuckLake runs in iad only; for DuckDB iad is recommended, since the dashboard, API and syncs run there. |
vmSize | string | shared-cpu-1x | See sizes. |
memoryMb | integer | 1024 | 256 to 32768. |
ttlHours | number | none | Delete the database automatically after this many hours. |
autoStop | boolean | false | Stop when idle. See stop when idle. |
curl -X POST https://duckhouse.co/api/v1/databases \
-H "Authorization: Bearer $DUCKHOUSE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "q3-analysis", "ttlHours": 72, "autoStop": true }'{
"database": {
"id": "cmfk2x9q10001",
"name": "q3-analysis",
"engine": "duckdb",
"engineVersion": "1.5.5",
"status": "provisioning",
"region": "iad",
"vmSize": "shared-cpu-1x",
"memoryMb": 1024,
"autoStop": true,
"expiresAt": "2026-09-23T18:00:00.000Z",
"connection": { "protocol": "quack", "uri": "quack:duckdb-a1b2c3d4e5.fly.dev:443" }
},
"token": "dh_…",
"connection": {
"uri": "quack:duckdb-a1b2c3d4e5.fly.dev:443",
"sql": "ATTACH 'quack:duckdb-a1b2c3d4e5.fly.dev:443' AS q3_analysis (TOKEN 'dh_…');"
}
}The token is returned by this call and never again. A new database starts as provisioning; poll GET /databases/:id until its status is running, usually about a minute.
One database, including its current status and connection address.
Delete a database and everything in it, permanently. Requires a full-scope key.
The database types that can be created right now.
Run a query
Run one SQL statement and return its rows.
| Field | Type | Default | |
|---|---|---|---|
sql | string | required | One statement, up to 100 KB. |
readOnly | boolean | false | Refuse anything that is not a plain query. Always on for read-scoped keys. |
maxRows | integer | 10000 | Up to 100000. Extra rows are dropped and reported. |
curl -X POST https://duckhouse.co/api/v1/databases/$DB/query \
-H "Authorization: Bearer $DUCKHOUSE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "sql": "SELECT status, count(*) AS n FROM stripe.invoices GROUP BY status" }'{
"columns": ["status", "n"],
"types": ["VARCHAR", "BIGINT"],
"rows": [
{ "status": "paid", "n": "1284" },
{ "status": "open", "n": "37" }
],
"rowCount": 2,
"truncated": false
}- The query runs on the server, so schema names, joins,
UPDATEandDELETEall work as written. None of the attachment limits apply here. - Large integers, decimals, dates and timestamps are returned as strings, so that no precision is lost in JSON.
- When
truncatedis true, the result was cut atmaxRows. Aggregate or filter in SQL rather than paging through a large table; for bulk export, attach with DuckDB andCOPYto a file.
Every table and view, with column names, types and nullability. Useful before generating SQL.
Connections
The same operations as the Connections section of the dashboard. Creating, changing and deleting require a full-scope key.
The available sources and the fields each one needs.
Check that a source can be reached, and list what could be synced, without saving anything.
The Connections feeding a database.
Create a Connection. The source is tested first, and the first sync starts immediately. Returns 409 if the database already has a Connection for a source that allows only one (every source except PostgreSQL, MySQL, Google Sheets and SFTP / FTP).
curl -X POST https://duckhouse.co/api/v1/databases/$DB/connections \
-H "Authorization: Bearer $DUCKHOUSE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "postgres",
"name": "Production replica",
"scheduleMinutes": 60,
"config": { "host": "db.example.com", "port": 5432, "database": "shop", "user": "duckhouse_reader" },
"secrets": { "password": "…" }
}'One Connection and the state of its last run. Secrets are never returned.
Rename, pause or resume (status: paused or active), reschedule, or replace the configuration and secrets.
What the source has now, and the per-table choices this Connection has saved. Change them with PATCH and config.streams, which replaces the saved list: enabled: false turns a table off, and excludeColumns (PostgreSQL and MySQL) lists columns never read.
Stop syncing. Tables already in the database are left in place.
Start a sync now. Returns immediately; follow progress through the runs.
Run history, most recent first, with rows synced per table and any error.