Asking Questions
Query your Chat Aid knowledge base and receive AI-generated answers with source citations.
Endpoint
POST https://api.chataid.com/chat/completions/custom
Authentication
Authorization: YOUR_API_KEY
Content-Type: application/json
No Bearer Prefix
Do not include "Bearer " before your API key.
How It Works
The API uses polling for asynchronous processing:
- Submit question → receive
promptIdandpollEndpoint - Poll endpoint at recommended
timeInterval - Stop when
canPollisfalse - Retrieve answer and sources
This ensures high-quality answers for complex queries.
Request Parameters
Submit Question
POST /chat/completions/custom
| Parameter | Type | Required | Description |
|---|---|---|---|
prompt | string | Yes | The question to answer |
parentTs | string | No | Unix timestamp for conversation threading |
messageTs | string | No | Unix timestamp of current message |
wikiFilters | object | No | Filter search scope (see Wiki Filters) |
Example
curl -X POST https://api.chataid.com/chat/completions/custom \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "What is our refund policy?"}'
{
"prompt": "What is our refund policy?"
}
Response
Initial Response
Status: 200 OK
{
"ok": true,
"promptId": "65e1c08202791119fbe1d476",
"pollEndpoint": "https://api.chataid.com/chat/completions/custom/65e1c08202791119fbe1d476",
"timeInterval": 5000,
"votingEndpoint": "https://api.chataid.com/chat/completions/feedback/65e1c08202791119fbe1d476"
}
| Field | Description |
|---|---|
promptId | Unique question identifier |
pollEndpoint | URL to poll for answer |
timeInterval | Recommended poll interval (milliseconds) |
votingEndpoint | URL for feedback submission |
Poll Response (Processing)
GET {pollEndpoint}
{
"ok": true,
"data": {
"canPoll": true,
"response": "Loading completions..."
}
}
Poll Response (Complete)
{
"ok": true,
"data": {
"canPoll": false,
"response": "Our refund policy allows customers to return products within 30 days...",
"sources": {
"formatted": "**Sources:**\n- [Refund Policy](https://...) (Confluence)",
"raw": [
{
"name": "Refund Policy",
"provider": "confluence",
"url": "https://docs.example.com/policies/refunds"
}
]
}
}
}
| Field | Description |
|---|---|
data.canPoll | false when answer is ready |
data.response | Answer text or loading message |
data.sources | Source citations (when ready) |
data.sources.formatted | Markdown-formatted sources |
data.sources.raw | Array of source objects |
Error Response
Status: 400 or 401
{
"ok": false,
"message": "promptId is invalid"
}
See Getting Started - Error Handling.
Polling Best Practices
- Respect
timeInterval- Use the returned interval - Check
canPoll- Stop whenfalse - Set timeout - Limit to 60 seconds total (~12 attempts)
- Handle errors - Catch network failures gracefully
- Cache results - Store answers for repeated questions
Wiki Filters
Restrict search scope by filtering teams.
{
"prompt": "What is the deployment process?",
"wikiFilters": {
"teams": ["team-id-1", "team-id-2"]
}
}
| Field | Description |
|---|---|
wikiFilters.teams | Array of team IDs to search within |
API Key Configuration
Teams must be accessible by your API key (configured in Settings → Custom APIs). The wikiFilters further restricts within those teams.
Conversation Threading
Maintain context across multiple questions using parentTs.
Example Flow
Question 1:
{
"prompt": "What is our refund policy?",
"parentTs": "1640995200"
}
Question 2 (follow-up):
{
"prompt": "What about international orders?",
"parentTs": "1640995200",
"messageTs": "1640995260"
}
Chat Aid understands "international orders" refers to refunds due to conversation context.
Best Practices
- Use unique
parentTsper conversation - Increment
messageTsfor follow-ups - Start new conversations for unrelated topics
- Conversations retained for 90 days
Code Examples
- JavaScript
- Python
- cURL
Complete JavaScript Implementation
const axios = require('axios');
class ChatAidClient {
constructor(apiKey) {
this.apiKey = apiKey;
this.baseURL = 'https://api.chataid.com';
}
async query(prompt, options = {}) {
// Submit question
const submitResponse = await axios.post(
`${this.baseURL}/chat/completions/custom`,
{
prompt,
parentTs: options.parentTs,
messageTs: options.messageTs,
wikiFilters: options.wikiFilters
},
{
headers: {
'Authorization': this.apiKey,
'Content-Type': 'application/json'
},
timeout: 30000
}
);
if (!submitResponse.data.ok) {
throw new Error(submitResponse.data.message);
}
const { promptId, pollEndpoint, timeInterval } = submitResponse.data;
// Poll for answer
const result = await this.pollForAnswer(pollEndpoint, timeInterval);
return {
promptId,
answer: result.response,
sources: result.sources
};
}
async pollForAnswer(pollEndpoint, interval, maxAttempts = 12) {
for (let attempt = 0; attempt < maxAttempts; attempt++) {
await new Promise(resolve => setTimeout(resolve, interval));
const response = await axios.get(pollEndpoint, {
headers: { 'Authorization': this.apiKey }
});
if (!response.data.ok) {
throw new Error(response.data.message);
}
const { canPoll, response: answer, sources } = response.data.data;
if (!canPoll) {
return { response: answer, sources };
}
}
throw new Error('Polling timeout');
}
}
// Usage
const client = new ChatAidClient(process.env.CHATAID_API_KEY);
// Simple query
const result = await client.query('What is our refund policy?');
console.log(result.answer);
// With filters
const result2 = await client.query('Find compliance docs', {
wikiFilters: { teams: ['team-123'] }
});
// Conversation
const parentTs = Date.now().toString();
const r1 = await client.query('What is our refund policy?', { parentTs });
const r2 = await client.query('What about international orders?', {
parentTs,
messageTs: (Date.now() + 1000).toString()
});
Python Implementation
import requests
import time
import os
CHATAID_API_KEY = os.environ['CHATAID_API_KEY']
def ask_question(prompt, parent_ts=None):
# Submit question
response = requests.post(
'https://api.chataid.com/chat/completions/custom',
json={'prompt': prompt, 'parentTs': parent_ts},
headers={'Authorization': CHATAID_API_KEY},
timeout=30
)
data = response.json()
poll_endpoint = data['pollEndpoint']
interval = data['timeInterval'] / 1000
# Poll for answer
for _ in range(12):
time.sleep(interval)
poll_response = requests.get(
poll_endpoint,
headers={'Authorization': CHATAID_API_KEY}
)
result = poll_response.json()['data']
if not result['canPoll']:
return result['response']
raise Exception('Timeout')
# Usage
answer = ask_question('What is our refund policy?')
print(answer)
cURL Example
# Submit
RESPONSE=$(curl -X POST https://api.chataid.com/chat/completions/custom \
-H "Authorization: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "What is our refund policy?"}' --silent)
POLL_ENDPOINT=$(echo $RESPONSE | jq -r '.pollEndpoint')
# Poll (repeat until canPoll is false)
curl $POLL_ENDPOINT -H "Authorization: YOUR_API_KEY"
Related Documentation
- Getting Started - Authentication and error handling
- Training Sources - Manage file uploads
- Custom APIs - Configure API keys
- Data Sources - Understand accessible data