Run a read-only SQL query
Executes a single read-only Postgres `SELECT` statement against a curated set of views scoped to this workspace. Call `GET /v1/sql/schema` first — it lists every queryable view (table) and column; unqualified names in your query (e.g. `FROM leads`) resolve against those views automatically. Only one top-level `SELECT` is allowed: no `INSERT`/`UPDATE`/`DELETE`/DDL, no `EXPLAIN`, no table-valued sources, no unbounded result constructors/collection aggregates, and no multiple statements — anything else is rejected with `400`. Results are capped at 10,000 rows or 8 MB of response body, whichever comes first (`truncated: true` when either cap is hit); the database query is stopped when that byte cap is reached, PostgreSQL temporary-file spill is capped at 64 MB per process, and a query is aborted after 30 seconds (`408`). A single row that alone exceeds the size budget is rejected with `400` rather than truncated — select fewer columns, or wrap large text in `left(col, 1000)`. Requires the `sql:query` permission and workspace enrollment in the SQL query private alpha (`403` otherwise, contact us to request access). Rate limited to 2 queries/second and one in-flight query per workspace (`429` when either limit is exceeded).
Executes a single read-only Postgres SELECT statement against a curated set of views scoped to this workspace. Call GET /v1/sql/schema first — it lists every queryable view (table) and column; unqualified names in your query (e.g. FROM leads) resolve against those views automatically. Only one top-level SELECT is allowed: no INSERT/UPDATE/DELETE/DDL, no EXPLAIN, no table-valued sources, no unbounded result constructors/collection aggregates, and no multiple statements — anything else is rejected with 400. Results are capped at 10,000 rows or 8 MB of response body, whichever comes first (truncated: true when either cap is hit); the database query is stopped when that byte cap is reached, PostgreSQL temporary-file spill is capped at 64 MB per process, and a query is aborted after 30 seconds (408). A single row that alone exceeds the size budget is rejected with 400 rather than truncated — select fewer columns, or wrap large text in left(col, 1000). Requires the sql:query permission and workspace enrollment in the SQL query private alpha (403 otherwise, contact us to request access). Rate limited to 2 queries/second and one in-flight query per workspace (429 when either limit is exceeded).
Authorization
ApiKeyAuth API key created under Settings → API Keys. Scoped to a single workspace.
In: header
Request Body
application/json
TypeScript Definitions
Use the request body type in TypeScript.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/sql/query" \ -H "Content-Type: application/json" \ -d '{ "query": "string" }'{ "columns": [ { "name": "string", "type": "string" } ], "rows": [ {} ], "rowCount": 0, "truncated": true, "executionMs": 0}Get the queryable SQL schema GET
Self-documentation for the SQL query interface: every view (table) you can `SELECT` from via `POST /v1/sql/query`, its columns (name, type, description), and the interface's limits. Call this before writing a query — this is a curated set of tenant-scoped views, not the full production schema, and `runSqlQuery` only accepts relations listed here. Requires the `sql:query` permission and workspace enrollment in the SQL query private alpha (`403` otherwise, contact us to request access).
Subscribe to events (create a webhook) POST
Registers a target URL to receive a `WebhookPayload` POST when a matching event fires — the subscribe step for a Zapier/Make instant trigger. Persist the returned `id` to unsubscribe later. Requires the `webhook:create` permission.