Appearance
API Reference
Complete reference for all Canny Bot API endpoints.
Base URL
https://api.canny.bot/api
Authentication
Include one of the following with every request:
API Key (Query Parameter):
?api_key=<your_api_key>
API Key (Header):
x-api-key: <your_api_key>
Widget Endpoints
Generate Widget ID
Create a new widget for your website.
POST /widget/generate
x-api-key: <your_api_key>
Response:
json
{
"data": {
"widgetId": "wgt_123_abc456",
"embedCode": "<script src=\"...\"></script>"
}
}
Get Widget Script
Retrieve the embeddable widget JavaScript.
GET /widget/script/:widget_id
Parameters:
widget_id(path): Widget ID
Response: JavaScript code (Content-Type: application/javascript)
Get Widget Info
Retrieve current widget configuration.
GET /widget/info
x-api-key: <your_api_key>
Response:
json
{
"data": {
"widgetId": "wgt_123_abc456",
"embedCode": "<script src=\"...\"></script>",
"color": "#667eea",
"greeting": "Hello! How can I help you today?",
"borderRadius": 16,
"buttonRadius": 50,
"buttonText": "Chat",
"font": "Arial",
"title": "Chat with us"
}
}
Customize Widget
Update widget appearance and behavior.
PUT /widget/customize
x-api-key: <your_api_key>
Content-Type: application/json
{
"widget_color": "#667eea",
"widget_greeting": "Hello!",
"widget_border_radius": 16,
"widget_button_radius": 50,
"widget_button_text": "Chat",
"widget_font": "Arial",
"widget_title": "Chat with us"
}
Response:
json
{
"data": {
"success": true
}
}
Chat (Non-Streaming)
Send a message to the widget chat.
POST /widget/chat
x-api-key: <your_api_key>
Content-Type: application/json
{
"widgetId": "wgt_123_abc456",
"sessionId": "sess_abc123",
"message": "What is your return policy?"
}
Response:
json
{
"data": {
"response": "Our return policy allows returns within 30 days...",
"sessionId": "sess_abc123"
}
}
Chat Stream
Send a message and receive streaming response.
POST /widget/chat/stream
Content-Type: application/json
{
"widgetId": "wgt_123_abc456",
"sessionId": "sess_abc123",
"message": "What is your return policy?"
}
Response Format (Server-Sent Events):
data: {"type":"sources","sources":[...]}
data: {"type":"content","content":"Our return "}
data: {"type":"content","content":"policy..."}
data: {"type":"done"}
Semantic Search Endpoints
Search
Find documents matching a query.
GET /semantic-search/search?query=<query>&limit=5&threshold=0.1
x-api-key: <your_api_key>
Query Parameters:
query(required): Search querylimit(optional): Max results (default: 5)threshold(optional): Relevance threshold 0-1 (default: 0.1)contentType(optional): Filter by content type
Response:
json
{
"data": [
{
"id": "chunk_123",
"title": "Return Policy",
"textSnippet": "We accept returns within 30 days...",
"fullContent": "Full content...",
"score": 0.87,
"documentId": "doc_1",
"contentType": "page"
}
],
"meta": {
"count": 1
}
}
Answer
Get an AI-generated answer based on search results.
GET /semantic-search/answer?query=<query>&limit=5&threshold=0.1
x-api-key: <your_api_key>
Query Parameters:
query(required): Questionlimit(optional): Source documents to use (default: 5)threshold(optional): Relevance threshold (default: 0.1)contentType(optional): Filter by content type
Response:
json
{
"data": {
"answer": "You can return items within 30 days...",
"sources": [
{
"id": "chunk_123",
"title": "Return Policy",
"textSnippet": "We accept returns within 30 days...",
"score": 0.87
}
]
},
"meta": {
"sourcesCount": 1
}
}
Answer Stream
Get a streaming AI-generated answer.
GET /semantic-search/answer/stream?query=<query>&limit=5&threshold=0.1
x-api-key: <your_api_key>
Response Format (Server-Sent Events):
data: {"type":"sources","sources":[...],"uniqueDocs":[...]}
data: {"type":"content","content":"You can "}
data: {"type":"content","content":"return items..."}
data: {"type":"done"}
Error Responses
400 Bad Request
json
{
"error": "Bad Request",
"message": "Query param is required"
}
401 Unauthorized
json
{
"error": "Unauthorized",
"message": "Authentication required. Use JWT token or api_key parameter"
}
404 Not Found
json
{
"error": "Not Found",
"message": "Widget not found"
}
429 Too Many Requests
json
{
"error": "Rate limit exceeded",
"message": "You have exceeded the rate limit of 10 requests per minute for your free plan.",
"retryAfter": 45
}
500 Internal Server Error
json
{
"error": "Internal Server Error",
"message": "An unexpected error occurred"
}
Rate Limits
Rate limits are enforced per plan:
| Plan | Monthly Limit | Requests/Second |
|---|---|---|
| Free | 100 | 1 |
| Pro | 1,000 | 5 |
| Enterprise | Unlimited | 20 |
Rate Limiting
All authenticated API endpoints are subject to rate limiting based on your plan:
| Plan | Requests/Minute |
|---|---|
| Free | 10 |
| Pro | 100 |
| Enterprise | 1000 |
Rate limit information is included in response headers:
X-RateLimit-Limit: 10
X-RateLimit-Remaining: 9
X-RateLimit-Reset: 1703341234
Retry-After: 45
When the rate limit is exceeded, the API returns a 429 status code with retry information.
Response Codes
| Code | Meaning |
|---|---|
| 200 | Success |
| 400 | Bad Request |
| 401 | Unauthorized |
| 404 | Not Found |
| 429 | Too Many Requests (Rate Limited) |
| 500 | Server Error |