SQL is powerful, but it is not always the interface people want to use.
Product managers want to ask which customers generated the most revenue. Support teams want to find pending orders. Operations teams want to check usage patterns. Developers and data teams can write the SQL, but the request often starts in plain English.
The sql-natural-language-python example shows how to turn those plain-English questions into structured, read-only SQL with Telnyx AI Inference.
Code:
What the example builds
The project is a Flask API with these routes:
POST /querygenerates SQL from a natural-language question and a provided schemaPOST /query/samplegenerates SQL and runs it against a bundled sample SQLite datasetPOST /validatedry-runs a SQL string against the sample datasetGET /querieslists recently generated queriesGET /queries/<id>fetches one query by IDGET /healthreturns service status
The generated response is structured JSON. A successful query can include:
idquestionsqlexplanationtables_usedis_selectdialectgenerated_at
For the sample route, the response also includes execution results:
columnsrowsrow_count
That makes the example useful as an app pattern, not just a prompt demo.
Why natural language to SQL needs guardrails
Natural language to SQL can be risky if the app simply asks a model for SQL and runs whatever comes back.
This example keeps the surface area small. The prompt asks for a single read-only query. The validation layer rejects multiple statements, comments, and write-oriented keywords such as INSERT, UPDATE, DELETE, DROP, ALTER, and TRUNCATE.
The sample execution path uses SQLite in memory with a bundled sample_schema.sql file. That lets you test the flow without pointing the app at a real production database.
The pattern is:
- receive a natural-language question
- include schema context
- ask Telnyx AI Inference for structured SQL output
- validate that the SQL is read-only
- optionally execute it against sample data
- return JSON that another app can display, store, or review
How it uses Telnyx AI Inference
The app sends requests to:
POST /v2/ai/chat/completions
The default model in .env.example is:
AI_MODEL=moonshotai/Kimi-K2.6
The prompt tells the model which SQL dialect to use and includes the schema DDL. It asks the model to return JSON with:
sqlexplanationtables_usedis_select
The Flask app parses the model response, adds metadata, stores recent queries in memory, and returns the result to the caller.
Run the example
Clone the examples repo:
git clone https://github.com/team-telnyx/telnyx-code-examples.git
cd telnyx-code-examples/sql-natural-language-python
Create your environment file:
cp .env.example .env
Add your Telnyx API key:
TELNYX_API_KEY=your_telnyx_api_key
AI_MODEL=moonshotai/Kimi-K2.6
HOST=127.0.0.1
Install dependencies and start the app:
pip install -r requirements.txt
python app.py
Check the server:
curl http://localhost:5000/health
Ask a question against the sample dataset:
curl -X POST http://localhost:5000/query/sample \
-H "Content-Type: application/json" \
-d '{"question": "Show me the top 3 customers by total order revenue"}' | python3 -m json.tool
Validate a read-only SQL statement:
curl -X POST http://localhost:5000/validate \
-H "Content-Type: application/json" \
-d '{"sql": "SELECT * FROM orders WHERE total > 100"}' | python3 -m json.tool
Generate SQL from your own schema:
curl -X POST http://localhost:5000/query \
-H "Content-Type: application/json" \
-d '{
"question": "Show me the top 10 customers by total order revenue",
"dialect": "postgresql",
"schema": "CREATE TABLE customers (id INT PRIMARY KEY, name TEXT); CREATE TABLE orders (id INT, customer_id INT, total REAL);"
}' | python3 -m json.tool
Where this pattern can go
A production version could add:
- authentication for internal users
- a persistent query history
- schema discovery from your data warehouse
- human approval before executing generated SQL
- row limits and cost controls
- a web UI for business users
- audit logs for every generated query
- database-specific validation for Postgres, Snowflake, or BigQuery
The core idea stays the same: use the model to translate intent into a query draft, then use normal application logic to validate, constrain, and route that output safely.