JavaScript integration
Generate SQL in your Node.js backend.
Use Node.js fetch to call TTSQL from a server route or worker. Return the generated SQL to a review step while keeping the API key on the server.
Try TTSQL freePrepare a project and a server-side API key
Create a TTSQL project, choose its database type and supply the schema context and project rules that generation should use. Create an API key for your account and record the intended project ID. Passing project_id explicitly avoids ambiguity when an account owns several projects.
Store the key in your server's environment or secret manager. Do not put it in source control, a browser bundle or a publicly shared notebook. TTSQL builds schema and policy context from the selected project; this request does not upload a database schema or connect to a database.
Use a maintained Node.js runtime
The example targets Node.js 22 or later and uses built-in fetch and AbortSignal.timeout, so no HTTP package is required. Save it as generate-sql.mjs, set TTSQL_API_KEY and TTSQL_PROJECT_ID in the server environment, then run node generate-sql.mjs.
A .mjs file enables ES modules. In a framework application, put the function in a server-only module and call it from an authenticated server route. Do not prefix the API key with a framework's public environment-variable prefix.
Validate the response before using the SQL
This function checks the project ID before sending JSON, gives the request a sixty-second abort signal, and requires a nonempty SQL string with executed set to false. The sample prompt assumes an orders table in the configured project.
An abort ends the client's wait; it does not guarantee cancellation of a generation already accepted by the server. The function deliberately makes one request so retries remain an explicit application decision.
export async function generateSql(prompt) {
const apiKey = process.env.TTSQL_API_KEY;
const rawProjectId = process.env.TTSQL_PROJECT_ID ?? "";
const projectId = Number(rawProjectId);
if (!apiKey?.trim() || !/^\d+$/.test(rawProjectId) ||
!Number.isSafeInteger(projectId) || projectId <= 0 ||
typeof prompt !== "string" || !prompt.trim()) {
throw new Error("A key, positive project ID and prompt are required");
}
const response = await fetch("https://ttsql.com/api/v1", {
method: "POST",
headers: {
"Content-Type": "application/json",
"Accept": "application/json",
"x-api-key": apiKey,
},
body: JSON.stringify({ prompt, project_id: projectId }),
signal: AbortSignal.timeout(60_000),
});
if (!response.ok) {
throw new Error(`TTSQL returned HTTP ${response.status}`);
}
const data = await response.json();
if (!data || data.status !== "success" ||
typeof data.query !== "string" || !data.query.trim()) {
throw new Error("Unexpected generation response");
}
if (data.executed !== false) {
throw new Error("Unexpected execution state; review the API contract");
}
return data.query;
}
try {
const sql = await generateSql(
"List paid order IDs and totals, ordered by ID, limited to 20 rows."
);
console.log(sql); // Review this SQL; this script does not execute it.
} catch (error) {
console.error(`Generation failed: ${error.name}`);
process.exitCode = 1;
}
Treat the response as generated SQL
A successful POST /api/v1 response includes status, query, executed, execution and metadata. This endpoint returns executed: false. Omitting the legacy execute field keeps the request focused on generation; sending execute: true does not enable execution.
The SQL is a candidate to review. Do not wire the returned string directly to a database driver. Manual Run in the TTSQL workspace is a separate action, with its own connection and policy checks.
{
"status": "success",
"query": "SELECT id, total FROM orders WHERE status = 'paid' ORDER BY id;",
"executed": false,
"execution": {"status": "not_requested"},
"metadata": {
"project_id": 123,
"api_key_id": 7,
"timestamp": "2026-09-05T12:00:00Z"
}
}
Put browser access behind your own server
A browser should call your application's authenticated route, not send your TTSQL key directly. The route should verify the user, select an authorized project and forward the prompt with the server-held key. CORS does not make a key embedded in client code secret.
Render generated SQL as text in a code viewer rather than assigning it to innerHTML. Use a review action before any execution workflow. Keep your application's authorization checks independent of whatever text the user puts in the prompt.
Handle failures without leaking prompts or credentials
Treat 400 as a request or policy problem to inspect, 401 as an authentication failure and 404 as a project access or identifier problem. A rate limit can produce 429. Generation or service failures can produce a server error. Consult the API reference for the deployed response contract.
The examples use one request and a finite timeout. A client timeout does not prove that server-side generation stopped. Avoid blind retries: a repeated POST can create another generation request. If you add bounded retries for temporary errors, account for rate limits and duplicate work.
Do not log the x-api-key header. Prompts and returned SQL can reveal business information and identifiers, so choose a deliberate logging policy instead of dumping entire requests and responses.
Answers before you connect a database.
Can I call TTSQL directly from a React component?
Do not expose a secret API key in a React browser bundle. Call your own authenticated server route and let that route hold the key and invoke TTSQL.
Does fetch execute the generated SQL?
No. fetch sends a generation request to POST /api/v1. The response returns executed: false; this example only prints the query for review.
Do I need Axios or a TTSQL JavaScript SDK?
No additional HTTP package is needed with the Node.js runtime used here. Other clients can send the same x-api-key header and JSON request body.
Bring your next question to TTSQL.
Start with one PostgreSQL project and 20 free requests a day. Explore your data, build a report, or integrate the API.