Appearance
Semantic Search API
The Semantic Search API allows you to search your knowledge base using natural language and get AI-generated answers based on relevant documents.
Overview
The Semantic Search API provides two main endpoints:
- Search: Find relevant documents matching a query
- Answer: Get an AI-generated answer based on search results
Both endpoints support streaming for real-time responses.
Features
- Natural Language Queries: Search using plain English, not keywords
- Semantic Understanding: Finds conceptually similar content, not just keyword matches
- AI-Generated Answers: Automatically synthesizes answers from multiple sources
- Streaming Responses: Real-time answer generation with Server-Sent Events (SSE)
- Source Attribution: Returns the documents used to generate answers
- Configurable Thresholds: Control relevance matching sensitivity
- Rate Limiting: Built-in usage tracking and limits
Authentication
All endpoints require authentication. You can use any of these methods:
API Key (Query Parameter):
bash
?api_key=<your_api_key>
API Key (Header):
bash
x-api-key: <your_api_key>
Search Endpoint
Search your knowledge base for documents matching a query.
Request
bash
GET https://api.canny.bot/api/semantic-search/search?query=<query>&limit=5&threshold=0.1&contentType=<type>
x-api-key: <your_api_key>
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
query | string | required | Your search query |
limit | number | 5 | Maximum number of results to return |
threshold | number | 0.1 | Relevance threshold (0-1, lower = more results) |
Response
json
{
"data": [
{
"id": "chunk_123",
"title": "Return Policy",
"textSnippet": "We accept returns within 30 days of purchase...",
"fullContent": "Full document content here...",
"score": 0.87,
"documentId": "doc_1"
},
{
"id": "chunk_124",
"title": "Shipping Information",
"textSnippet": "Standard shipping takes 5-7 business days...",
"fullContent": "Full document content here...",
"score": 0.72,
"documentId": "doc_2"
}
],
"meta": {
"count": 2
}
}
Example
bash
curl -X GET "https://api.canny.bot/api/semantic-search/search?query=how%20do%20I%20return%20an%20item&limit=3" \
-H "x-api-key: <your_api_key>"
Answer Endpoint
Get an AI-generated answer based on semantic search results.
Request
bash
GET https://api.canny.bot/api/semantic-search/answer?query=<query>&limit=5&threshold=0.1
x-api-key: <your_api_key>
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
query | string | required | Your question |
limit | number | 5 | Number of source documents to use |
threshold | number | 0.1 | Relevance threshold (0-1) |
Response
json
{
"data": {
"answer": "You can return items within 30 days of purchase. Simply contact our support team with your order number and reason for return. We'll provide you with a prepaid shipping label.",
"sources": [
{
"id": "chunk_123",
"title": "Return Policy",
"textSnippet": "We accept returns within 30 days...",
"score": 0.87
},
{
"id": "chunk_124",
"title": "Shipping Information",
"textSnippet": "Standard shipping takes 5-7 business days...",
"score": 0.72
}
]
},
"meta": {
"sourcesCount": 2
}
}
Example
bash
curl -X GET "https://api.canny.bot/api/semantic-search/answer?query=how%20do%20I%20return%20an%20item" \
-H "x-api-key: <your_api_key>"
Streaming Answer Endpoint
Get real-time streaming answers using Server-Sent Events (SSE).
Request
bash
GET https://api.canny.bot/api/semantic-search/answer/stream?query=<query>&limit=5
x-api-key: <your_api_key>
Response Format
The endpoint returns Server-Sent Events with the following message types:
data: {"type":"sources","sources":[{"id":"chunk_123","title":"Return Policy","textSnippet":"...","score":0.87}],"uniqueDocs":[{"id":"doc_1","title":"Return Policy","url":"https://..."}]}
data: {"type":"content","content":"You can "}
data: {"type":"content","content":"return items "}
data: {"type":"content","content":"within 30 days..."}
data: {"type":"done"}
Message Types
| Type | Description | Payload |
|---|---|---|
sources | Initial sources and unique documents | sources, uniqueDocs |
content | Streamed answer content (chunks) | content |
done | Stream complete | (empty) |
error | Error occurred | error |
Example (JavaScript)
javascript
const eventSource = new EventSource(
"https://api.canny.bot/api/semantic-search/answer/stream?query=how%20do%20I%20return%20an%20item"
);
let fullAnswer = "";
eventSource.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.type === "sources") {
console.log("Sources:", data.sources);
} else if (data.type === "content") {
fullAnswer += data.content;
console.log("Streaming:", fullAnswer);
} else if (data.type === "done") {
console.log("Complete answer:", fullAnswer);
eventSource.close();
}
};
eventSource.onerror = (error) => {
console.error("Stream error:", error);
eventSource.close();
};
Usage Limits
Each plan has monthly interaction limits:
- Free Plan: 100 interactions/month
- Pro Plan: 1,000 interactions/month
- Enterprise: Unlimited
When limits are exceeded, the API returns a 429 (Too Many Requests) response:
json
{
"error": "Monthly interaction limit exceeded",
"message": "You have used 100 of 100 interactions this month. Please upgrade your plan for more interactions.",
"currentUsage": 100,
"limit": 100
}
Best Practices
Query Optimization
Be specific: More detailed queries return better results
- ❌ "return"
- ✅ "how do I return an item within 30 days?"
Use natural language: Write like you're asking a person
- ❌ "return policy days"
- ✅ "what's your return policy?"
Ask one question at a time: Multiple questions reduce accuracy
- ❌ "What's your return policy and shipping cost?"
- ✅ "What's your return policy?"
Threshold Tuning
- Lower threshold (0.1-0.3): More results, lower relevance
- Higher threshold (0.5-0.8): Fewer results, higher relevance
- Default (0.1): Good balance for most use cases
Error Handling
javascript
try {
const response = await fetch(
"https://api.canny.bot/api/semantic-search/answer?query=...",
{ headers: { Authorization: "Bearer ..." } }
);
if (response.status === 429) {
// Handle rate limit
const error = await response.json();
console.error("Limit exceeded:", error.message);
} else if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
const result = await response.json();
console.log("Answer:", result.data.answer);
} catch (error) {
console.error("Error:", error);
}
Response Times
- Search: 200-500ms (depends on knowledge base size)
- Answer: 1-3 seconds (includes LLM processing)
- Streaming Answer: 2-5 seconds (real-time chunks)
Troubleshooting
No results returned?
- Check that documents are uploaded and indexed
- Try a lower threshold value
- Use more specific query terms
Poor answer quality?
- Ensure source documents contain relevant information
- Try a more specific query
- Increase the
limitparameter to use more sources
Rate limit exceeded?
- Upgrade your plan for more interactions
- Implement caching for common queries
- Batch requests if possible
Slow responses?
- This is normal for the first request (model initialization)
- Subsequent requests should be faster
- Consider using streaming for better UX