Query API
The Query API lets you take the logic and structure you define in Qluent and use it outside the product. Ask questions in plain English and receive structured data responses—perfect for building AI experiences.
Getting started
Prerequisites
- A Qluent project with connected data sources
- Project owner permissions (required to manage API keys)
Creating an API key
- Navigate to Project Settings → API Settings
- Click Create API Key
- Enter a descriptive name (e.g., "Slack Integration", "Query agent")
- Copy the key immediately—it will only be shown once
We store only a one-way hash of your key. If you lose it, you'll need to create a new one.
Authentication
All requests require your key in the X-API-Key header:
curl -X POST "https://api.qluent.io/api/v1/query/" \
-H "X-API-Key: qk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{"question": "What were total sales last month?", "user_email": "analyst@company.com"}'
Making requests
Endpoint
POST https://api.qluent.io/api/v1/query/
Request body
| Field | Type | Required | Description |
|---|---|---|---|
question | string | Yes | Natural language question to answer |
user_email | string | Yes | Email of the user making the request (for audit) |
thread_id | string | Thread ID for follow-up questions |
Example request
curl -X POST "https://api.qluent.io/api/v1/query/" \
-H "X-API-Key: qk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"question": "What were total sales last month?",
"user_email": "analyst@company.com"
}'
Example response
{
"success": true,
"thread_id": "thr_abc123",
"message_id": "msg_def456",
"question": "What were total sales last month?",
"sql": "SELECT SUM(amount) FROM sales WHERE date >= '2024-01-01'",
"explanation": "Total sales last month were $125,000 across 847 transactions.",
"data": [{"total_sales": 125000, "transaction_count": 847}],
"columns": ["total_sales", "transaction_count"],
"row_count": 1
}
Large result handling
For queries returning more than 1,000 rows, the response includes URLs for accessing the full dataset:
| Field | Type | Description |
|---|---|---|
download_url | string | URL to download results as CSV. Requires browser authentication. |
google_sheets_url | string | URL to open results in Google Sheets. Requires OAuth consent on first use. |
When these URLs are present, the data array contains only the first 1,000 rows. Use the URLs to access the complete dataset.
Follow-up questions
Continue a conversation by including the thread_id from the previous response:
curl -X POST "https://api.qluent.io/api/v1/query/" \
-H "X-API-Key: qk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"question": "Break that down by region",
"thread_id": "thr_abc123",
"user_email": "analyst@company.com"
}'
Streaming responses (SSE)
For real-time progress updates during query execution, use the streaming endpoint:
POST https://api.qluent.io/api/v1/query/stream
The request body is the same as the standard endpoint. The response is a Server-Sent Events stream with these event types:
| Event | Description |
|---|---|
status | Processing status updates |
sql | The generated SQL query |
result | Final query result with data |
clarification | Question requires clarification |
error | Error occurred during processing |
Feedback endpoint
Submit feedback on query responses to help improve result quality.
Endpoint
POST https://api.qluent.io/api/v1/feedback/
Request body
| Field | Type | Required | Description |
|---|---|---|---|
message_id | string | Yes | The message_id from a query response |
positive | boolean | Yes | true for positive feedback, false for negative |
comment | string | No | Optional feedback text (max 10,000 chars) |
user_email | string | Yes | Email of user submitting feedback (must have project access) |
Example request
curl -X POST "https://api.qluent.io/api/v1/feedback/" \
-H "X-API-Key: qk_your_api_key_here" \
-H "Content-Type: application/json" \
-d '{
"message_id": "msg_def456",
"positive": true,
"comment": "Exactly what I needed",
"user_email": "analyst@company.com"
}'
Example response
{
"success": true,
"feedback_id": 123,
"message": "Feedback submitted successfully"
}
Error codes
| Error Code | HTTP Status | Description |
|---|---|---|
INVALID_REQUEST | 400 | Malformed request body |
INVALID_API_KEY | 401 | Invalid or missing API key |
USER_NOT_AUTHORIZED | 403 | User does not have access to this project |
MESSAGE_NOT_FOUND | 404 | Invalid message_id or not in project |
Error handling
| Error Code | HTTP Status | Description |
|---|---|---|
INVALID_REQUEST | 400 | Malformed request body |
INVALID_API_KEY | 401 | Invalid or missing API key |
USER_NOT_AUTHORIZED | 403 | User does not have access to this project |
PROJECT_NOT_FOUND | 404 | Project not found |
THREAD_NOT_FOUND | 404 | Thread not found or expired |
CLARIFICATION_NEEDED | 422 | Question requires clarification |
CANNOT_ANSWER | 422 | Question cannot be answered with available data |
RATE_LIMIT_EXCEEDED | 429 | Too many requests |
EXECUTION_ERROR | 500 | Failed to execute query |
DATA_SOURCE_ERROR | 502 | Unable to connect to data source |
SERVICE_UNAVAILABLE | 503 | Service temporarily unavailable |
QUERY_TIMEOUT | 504 | Query execution timed out |
Rate limits
| Limit | Value |
|---|---|
| Requests per minute | 100 per project |
| Concurrent requests | 10 per project |
| Max query execution time | 5 minutes |
When rate limited, implement exponential backoff using the retry_after field in the response.
Security FAQ
How are API keys generated and stored?
Your API key is generated using cryptographically secure randomness. The full key (qk_...) is shown only once at creation—we never store or display it again. We store only a one-way hash, so even if our database were compromised, your actual key cannot be recovered.
How does authentication work?
Every API request requires your key in the X-API-Key header. We hash the incoming key and compare it against stored hashes—your raw key never touches our database. Keys are project-scoped, meaning a key can only access data within its assigned project.
How is streaming secured?
The SSE streaming endpoint uses the same API key authentication as the standard query endpoint. All data is transmitted over HTTPS with TLS encryption. Each event in the stream is authenticated as part of the same request that provided the API key.
Can I encrypt API responses?
Yes. You can configure PGP encryption per API key:
- Upload your PGP public key in API Settings
- All responses are encrypted with your public key before transmission
- Only you can decrypt with your private key
Even Qluent cannot read the encrypted payload. Encryption can be enabled, updated, or removed at any time from Project Settings → API Settings.
Who can manage API keys?
Only project owners can create, configure, or revoke API keys. Keys can be instantly revoked if compromised. We track last_used_at so you can audit key activity.
What about rate limiting?
Per-project rate limits prevent abuse. Rate limit headers in every response let you monitor your usage.
Managing keys
- View keys: Project Settings → API Settings
- Revoke keys: Click Revoke next to any key (takes effect immediately)
- Configure encryption: Click Configure to upload your PGP public key
Revoked keys stop working instantly. Applications using the key will receive 401 errors.