ZangTable exposes a read-only SQL query endpoint for reporting, lookups, joins, and debugging data relationships. Index endpoints help speed up common filters and sorts, especially when a table starts getting larger.
Use the query endpoint when you want to answer questions like:
- “Which members have overdue library books?”
- “Which customers have open invoices?”
- “Which orders should be merged with shipment rows by
order_id?”
- “What query shape should I turn into a dedicated app endpoint later?”
The query endpoint is read-only. Use record and schema endpoints for writes.
Read-only query
curl -X POST "$BASE_URL/projects/$PROJECT/query" \
-H "Authorization: Bearer $ZANGTABLE_TOKEN" \
-H "Content-Type: application/json" \
--data '{"sql":"SELECT id, title FROM books WHERE status = ?","params":["late"]}'
Example response:
{
"ok": true,
"data": {
"rows": [
{"id": 101, "title": "The Pragmatic Programmer"},
{"id": 102, "title": "Clean Architecture"}
],
"row_count": 2,
"limit": 500,
"duration_ms": 4
},
"error": null
}
Relational example: find members with late library books
First, fetch late loans:
curl -X POST "$BASE_URL/projects/$PROJECT/query" \
-H "Authorization: Bearer $ZANGTABLE_TOKEN" \
-H "Content-Type: application/json" \
--data '{"sql":"SELECT member_id, book_id, due_date FROM loans WHERE returned_at IS NULL AND due_date < ?","params":["2026-06-01"]}'
{
"ok": true,
"data": {
"rows": [
{"member_id": 7, "book_id": 101, "due_date": "2026-05-20"},
{"member_id": 9, "book_id": 102, "due_date": "2026-05-22"}
],
"row_count": 2
},
"error": null
}
Then fetch the matching members:
curl -X POST "$BASE_URL/projects/$PROJECT/query" \
-H "Authorization: Bearer $ZANGTABLE_TOKEN" \
-H "Content-Type: application/json" \
--data '{"sql":"SELECT id, email, name FROM members WHERE id IN (?, ?)","params":[7,9]}'
{
"ok": true,
"data": {
"rows": [
{"id": 7, "email": "ada@example.com", "name": "Ada"},
{"id": 9, "email": "grace@example.com", "name": "Grace"}
],
"row_count": 2
},
"error": null
}
Your backend can merge those results by member_id / id and send reminder emails to members with late books. Once the pattern is stable, you can also run it as one SQL query with a join:
SELECT members.id, members.email, members.name, loans.book_id, loans.due_date
FROM members
JOIN loans ON loans.member_id = members.id
WHERE loans.returned_at IS NULL AND loans.due_date < ?
Indexes
Use indexes when the same columns power frequent filters, sorts, joins, or dashboard views. For example, if you often query late loans by returned_at and due_date, create an index on those columns so SQLite can find matching rows faster.