Ask endpoints
An ask endpoint accepts a natural-language question, generates a
SELECT against the database’s schema, runs it, and returns both the
answer and the SQL. Unlike the in-product agent,
this is a public endpoint your end users can call.
{ "slug": "ask", "name": "Ask the data", "kind": "ask", "method": "POST", "sql": "", "input": [ { "name": "question", "type": "text", "required": true, "maxLength": 500 } ], "output": "answer", "auth": "public", "askConfig": { "allowedTables": ["orders", "customers"], "context": "Currency is USD. Customers without orders are inactive.", "maxRows": 50 }, "rateLimit": { "perMin": 5, "perDay": 200 }, "captcha": true}The sql field is ignored — the runtime fills it from the model’s
output. Input must include exactly one question field of type text.
What the runtime does
Section titled “What the runtime does”- Builds a schema snapshot for
askConfig.allowedTables(or every table when the array is empty). - Composes a prompt: schema + optional
askConfig.context+ the user’s question + a strict “SELECT only, single statement” system message. - Sends to Workers AI; rejects any output that fails
assertReadOnly. - Wraps the generated SQL:
SELECT * FROM (<generated>) LIMIT <maxRows>. - Executes against the DO, returns columns / rows / SQL / explanation.
Response
Section titled “Response”{ "ok": true, "data": { "sql": "SELECT COUNT(*) AS n FROM orders WHERE created_at > date('now','-7 day')", "explanation": "Counted orders with created_at within the last 7 days.", "columns": ["n"], "rows": [[42]] }}Why allow-listing matters
Section titled “Why allow-listing matters”askConfig.allowedTables is the only safety net between an arbitrary
user question and your full schema. Producers should:
- Allow-list narrowly. Only the tables you’d be comfortable showing in a public report.
- Lean on captcha + rate limits.
askcalls cost both Workers AI inference and DB reads. - Pair with
auth: "session"if you want each user to only see their own rows.$user_idis bound automatically; instruct the model inaskConfig.contextto filter by it.