SQL
Browse tables and run SQL against a database or one of its branches.
Every call here takes an optional environmentId (query or body) to run against that environment's branch. Without it, the primary (production) branch is used.
Tables
/databases/{databaseId}/tablespublic schema.{ "success": true, "data": [ { "name": "todos", "type": "BASE TABLE", "columnCount": 2 } ] }/databases/{databaseId}/tables/{table}/columns{ "success": true, "data": [ { "name": "id", "type": "integer", "nullable": false, "default": "nextval('todos_id_seq'::regclass)" }, { "name": "title", "type": "text", "nullable": false, "default": null } ] }/databases/{databaseId}/tables/{table}/rowslimit 1 to 200 (default 50) and offset.Run a statement
/databases/{databaseId}/queryProp
Type
curl -X POST https://api.helipod.io/api/databases/$DB/query \
-H "Authorization: Bearer hel_your_key" -H "Content-Type: application/json" \
-d '{ "sql": "select id, title from todos where title ilike $1", "params": ["%milk%"] }'{
"success": true,
"data": { "readOnly": true, "command": "select", "fields": ["id", "title"], "rows": [ { "id": 1, "title": "Buy milk" } ], "rowCount": 1, "truncated": false }
}At most 200 rows come back; truncated: true means there were more. Use limit and offset in your SQL to page.
Read-only by default
SELECT,WITH,EXPLAIN,SHOW,TABLEandVALUESrun in a read-only transaction.- Anything that changes data or schema (
INSERT,UPDATE,DELETE,CREATE,ALTER,DROP,TRUNCATE,GRANT, ...) answers428 WRITE_NOT_ALLOWEDunless you send"allowWrite": true. SET,RESET,LISTEN,NOTIFYandLOCKare always refused, because they change the session rather than your data.
curl -X POST https://api.helipod.io/api/databases/$DB/query \
-H "Authorization: Bearer hel_your_key" -H "Content-Type: application/json" \
-d '{ "sql": "insert into todos (title) values ($1) returning id", "params": ["Buy milk"], "allowWrite": true }'{ "success": true, "data": { "readOnly": false, "command": "insert", "fields": ["id"], "rows": [ { "id": 1 } ], "rowCount": 1, "truncated": false } }Check a statement first
/databases/{databaseId}/query/classifycurl -X POST https://api.helipod.io/api/databases/$DB/query/classify \
-H "Authorization: Bearer hel_your_key" -H "Content-Type: application/json" \
-d '{ "sql": "delete from todos where done" }'{
"success": true,
"data": {
"command": "delete",
"readOnly": false,
"writes": true,
"statements": [ { "command": "delete", "readOnly": false } ],
"requiresAllowWrite": true
}
}Use it to decide whether to ask a person before running a statement. requiresAllowWrite: true means /query needs "allowWrite": true. Several statements, or SET, LISTEN and similar session statements, answer 400 SQL_ERROR here as they would on /query.
Errors from Postgres
An error in your statement comes back as 400 SQL_ERROR with Postgres's own message, for example relation "todo" does not exist.
Migrations
This endpoint is for quick queries, admin fixes and agents. For your app's schema, keep migrations in your repository (Prisma, Drizzle, Alembic, ...) and run them with the connection string. Try them on a staging branch first.