Run SQL
POST /projects/:projectid/databases/:dbid/query
Run an arbitrary statement.
Runs the SQL you send against the database and returns any rows it produced. Use this for joins, aggregates and anything the structured endpoints cannot express.
Authentication
- Project API key: The credential for everything external. Created in Project Settings, bound to one project, and limited to the scopes it was granted. Format:
proj.<keyId>.<secret>. - Required permission:
databases.queryon :dbid.
Path parameters
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
projectid | string | Yes | - | The project id. |
dbid | string | Yes | - | The database id. |
Request body
Content type: application/json
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
query | string | Yes | - | The SQL statement to run. |
Example
{
"query": "SELECT customer, SUM(total) AS spend FROM orders GROUP BY customer ORDER BY spend DESC LIMIT 10;"
}
Example request
curl -X POST \
-H "Authorization: proj.KEY_ID.SECRET" \
-H "Content-Type: application/json" \
-d '{"query":"SELECT customer, SUM(total) AS spend FROM orders GROUP BY customer ORDER BY spend DESC LIMIT 10;"}' \
{{BASE_URL}}/projects/{{PROJECT_ID}}/databases/DATABASE_ID/query
Responses
200
The rows the statement produced.
{
"rows": [
{
"customer": "ada",
"spend": 512.25
}
]
}
403
The key lacks the Run SQL permission.
Notes
- This grant is as powerful as the worst statement it could carry. A
SELECTand aDROP TABLEare indistinguishable without parsing, so there is no heuristic that reads the statement and decides — grant Run SQL only where you would be comfortable granting full control of the database. - The statement runs under the database's query timeout. Long scans will be cut off rather than held open.