Discovery: explore, fields and tables
Five read routes describe a deployed branch without planning anything you have to run. They are what a field picker, an autocomplete or an agent calls before building a spec. Every one takes the same Authorization: Bearer header as /sql and works with query keys and personal keys.
| route | returns |
|---|---|
POST .../explore | the dimensions and measures a given query can still add |
GET .../fields?q=&hidden= | every field, optionally searched |
GET .../tables | every table with its fields |
GET .../branches/{branch} | the branch summary |
GET /projects | the projects and branches the key can see |
... is /projects/{uid}/branches/{branch} throughout.
explore
Given a query, which other fields could join it without breaking it? Send the same body as /sql (spec or expr, optional q). A context is accepted and ignored: exploring is about the model, not about rows.
curl -s https://app.0sql.io/projects/tpcds/branches/main/explore \
-H "Authorization: Bearer zqk_..." \
-H "Content-Type: application/json" \
-d '{"expr": "category, web net paid", "q": "date"}' zsql explore --expr 'category, web net paid' -q datedate dim Date web_sales, store_sales, date_dim ~1.00
ws_sold_date dim Web Sold Date web_sales ~0.67
-- can add 2 dimensions, 0 measures · server 210 us const res = await fetch("https://app.0sql.io/projects/tpcds/branches/main/explore", {
method: "POST",
headers: { Authorization: `Bearer ${key}`, "Content-Type": "application/json" },
body: JSON.stringify({ spec: currentSpec, q: userTyped }),
});
const { dimensions, measures } = await res.json(); {
"dimensions": [
{"uid": "date", "name": "Date", "data_type": "date", "description": "Calendar date",
"tables": ["web_sales", "store_sales", "date_dim"], "score": 1.0},
{"uid": "ws_sold_date", "name": "Web Sold Date", "data_type": "date", "description": "",
"tables": ["web_sales"], "score": 0.67}
],
"measures": [],
"total_us": 210
}
- Without
qevery addable field is listed, dimensions and measures separately, andscoreis absent. - With
q, only fields whose name contains the term (score1.0) or that are trigram-near it (score at least 0.5) are kept, best first. - Hidden fields are never listed.
Use it to drive a picker: after each selection, send the current spec and show only what comes back, so the user cannot build a query the planner will refuse. Agents get the same guarantee: a loop of explore, pick, explore converges on a plannable spec without guessing field names.
fields
curl -s "https://app.0sql.io/projects/tpcds/branches/main/fields?q=paid" \
-H "Authorization: Bearer zqk_..."
{"fields": [
{"uid": "net_paid", "name": "Net Paid", "kind": "measure", "data_type": "decimal",
"description": "Store sales net paid", "synonyms": ["revenue"], "tags": [],
"hidden": false, "tables": ["store_sales"], "score": 1.0},
{"uid": "ws_net_paid", "name": "Web Net Paid", "kind": "measure", "data_type": "decimal",
"description": "Web sales net paid", "synonyms": [], "tags": [],
"hidden": false, "tables": ["web_sales"], "score": 1.0},
{"uid": "ws_paid_inc_tax", "name": "Web Paid Inc Tax", "kind": "measure", "data_type": "decimal",
"description": "", "synonyms": [], "tags": [], "hidden": false, "tables": ["web_sales"], "score": 1.0}
]}
| param | effect |
|---|---|
q | containing matches first (score 1), then fuzzy matches with their trigram score |
hidden | true includes hidden fields |
Without q the whole catalogue is returned and score is absent. kind is dimension or measure. tags are the policy trigger tags from the model. CLI: zsql fields paid, zsql fields --hidden.
tables
curl -s https://app.0sql.io/projects/tpcds/branches/main/tables \
-H "Authorization: Bearer zqk_..."
{"tables": [
{"uid": "store_sales", "name": "Store Sales", "physical_name": "store_sales", "cost": 100,
"datasource": "warehouse", "fields": ["net_paid", "ss_sold_date", "customer_id", "..."]},
{"uid": "web_sales", "name": "Web Sales", "physical_name": "web_sales", "cost": 100,
"datasource": "warehouse", "fields": ["ws_net_paid", "ws_sold_date", "..."]},
{"uid": "item", "name": "Item", "physical_name": "item", "cost": 10,
"datasource": "warehouse", "fields": ["category", "product_name", "..."]},
{"uid": "date_dim", "name": "Date", "physical_name": "date_dim", "cost": 1,
"datasource": "warehouse", "fields": ["date"]}
]}
cost is the model’s planning cost (the resolver prefers cheaper tables); fields lists field uids. The table uids are what the spec’s hints key accepts. CLI: zsql tables.
branch summary
curl -s https://app.0sql.io/projects/tpcds/branches/main \
-H "Authorization: Bearer zqk_..."
{"project": "tpcds", "branch": "main", "deployed_at": "2026-10-01 15:04",
"datasources": 1, "tables": 6, "fields": 42, "joins": 5, "paths": 9, "policies": 1,
"tests": 3, "warnings": []}
The same counts a deploy prints, minus the test results. CLI: zsql status.
projects
curl -s https://app.0sql.io/projects -H "Authorization: Bearer zqk_..."
{"deployments": [
{"project": "tpcds", "branch": "main", "deployed_at": "2026-10-01 15:04",
"datasources": 1, "tables": 6, "fields": 42, "joins": 5, "paths": 9, "policies": 1, "tests": 3, "warnings": []}
],
"projects": [
{"uid": "tpcds", "name": "TPC-DS", "production_branch": "main", "visibility": "account",
"protected_production": false, "level": "read"}
]}
deployments is one summary per deployed branch the key can read; projects lists each project with the caller’s access level (read, write or owner). A query key sees only the projects and branches it is granted. CLI: zsql list. See Accounts and keys.
Next steps
- Shorthand expressions to turn a picked field list into a request
- Explain
- API reference for the complete route list