REST API reference
All endpoints are versioned under /api/v1 and require a bearer token scoped to the target database.
Base URL
https://wamsqlite.rendovations.com/api/v1
Run statements
POST /databases/{database}/query
Executes one or more SQL statements in order against the database. Statements are pre-split by the client — each array entry is exactly one statement, with no trailing semicolon required.
Request body
{
"statements": [
"SELECT * FROM users WHERE id = 1",
{
"sql": "SELECT * FROM users WHERE email = ?",
"params": ["ada@example.com"]
},
{
"sql": "UPDATE users SET last_seen_at = CURRENT_TIMESTAMP WHERE id = :id",
"params": { "id": 1 }
}
]
}
Each entry may be a plain SQL string, or an object with sql and optional bound
params (positional list for ?, or named map for :name / name).
Prefer bound parameters whenever values come from users — that is how you prevent classic SQL injection
in your application code. See Security.
Response — all statements succeed (200)
{
"database": "3f9a1b2c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"results": [
{
"sql": "SELECT * FROM users WHERE id = 1",
"columns": ["id", "name", "email"],
"rows": [{ "id": 1, "name": "Ada Lovelace", "email": "ada@example.com" }],
"rows_affected": 1,
"last_insert_id": null,
"time_ms": 0.42
},
{
"sql": "SELECT * FROM users WHERE email = ?",
"columns": ["id", "name", "email"],
"rows": [{ "id": 1, "name": "Ada Lovelace", "email": "ada@example.com" }],
"rows_affected": 1,
"last_insert_id": null,
"time_ms": 0.28
},
{
"sql": "UPDATE users SET last_seen_at = CURRENT_TIMESTAMP WHERE id = :id",
"columns": [],
"rows": [],
"rows_affected": 1,
"last_insert_id": null,
"time_ms": 0.31
}
],
"error": null
}
Response — a statement fails (400)
Execution stops at the first failing statement. results contains every statement that succeeded before it; the failing one and everything after it are not run.
{
"database": "3f9a1b2c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"results": [],
"error": {
"statement_index": 0,
"sql": "SELECT * FROM does_not_exist",
"message": "no such table: does_not_exist"
}
}
Security
WamSQLite executes the SQL you send against your database. That means table names, column names, and full query structure cannot be “blocked as injection” without breaking the product — the same model as Turso or similar SQLite hosts.
What is protected:
- Bound parameters — use
paramsfor user-supplied values so they cannot rewrite SQL. - Sandboxing —
ATTACH/DETACH,load_extension(),VACUUM INTO,readfile/writefile, and encryption key pragmas are blocked so a query cannot reach other files on the server. - One statement per entry — smuggling extra statements behind a semicolon in a single array item is rejected.
- Scoped tokens — bearer tokens work only for one database; read-only tokens cannot run writes.
Recommended client pattern:
{
"statements": [
{
"sql": "SELECT * FROM users WHERE id = ? AND status = ?",
"params": [42, "active"]
}
]
}
Inspect the schema
GET /databases/{database}/schema
Lists every table and view in the database, along with its row count.
{
"database": "3f9a1b2c-4d5e-4f6a-8b9c-0d1e2f3a4b5c",
"tables": [
{ "name": "users", "type": "table", "row_count": 128 }
]
}
Limits
| Limit | Value |
|---|---|
| Requests per minute | 120, per database |
| Statements per request | 50 |
| Max statement length | 100,000 characters |
| Max bind params per statement | 200 |
| Databases per account | 10 |