Execute read-only ClickHouse SQL queries against your Formo analytics data warehouse via the API. Returns structured results for events, users, and sessions.
Run a read-only SQL query to read your data. See examples on the Explorer page.Documentation Index
Fetch the complete documentation index at: https://docs.formo.so/llms.txt
Use this file to discover all available pages before exploring further.

query:read permission. Send it in the Authorization header:
POST/v0/querySELECT/WITH statement (read-only).LIMIT is required and must be <= 1000.200 OK returns rows plus pagination metadata reflecting the LIMIT / OFFSET you wrote into the SQL.
| Field | Type | Description |
|---|---|---|
data | array | Result rows |
total | integer | Total rows before LIMIT was applied |
limit | integer | LIMIT echoed from the SQL |
offset | integer | OFFSET echoed from the SQL |
has_more | boolean | true if total > offset + data.length |
limit/offset (not page/size) because the client controls pagination directly through the SQL query - Formo just echoes the values back.
error.code; see Errors for the full reference.
400 BAD_REQUEST: missing query, invalid SQL, LIMIT over 1000, or missing project id.401 UNAUTHORIZED: missing/invalid authorization header or API key.403 FORBIDDEN: API key lacks query:read scope.404 NOT_FOUND: project or read token not found.429 TOO_MANY_REQUESTS: per-workspace rate limit exceeded.500 INTERNAL_SERVER_ERROR: failure executing the query.Workspace API key (e.g. formo_xxx). Create one in the Formo dashboard under Team Settings > API Keys.
SQL query to execute
Offset-paginated query results. The server doesn't own pagination here - LIMIT and OFFSET come from your SQL string and are echoed back. total is the row count before LIMIT was applied; has_more is true when there are additional rows beyond the current window.
Result rows.
Total rows before LIMIT was applied.
Applied LIMIT (parsed from your SQL; defaults to the server cap if absent).
Applied OFFSET (parsed from your SQL; 0 if absent).
True when offset + data.length < total - i.e. there's another page to fetch by re-running with a higher OFFSET.