1. Overview
The Chat.co API allows you to programmatically integrate your chatbots into custom applications, websites, and workflows. With this API, you can create and manage conversations, send messages, receive AI-powered responses, and stream responses in real-time.
Looking for AI agent integrations? This page covers the direct HTTP API. If you want Claude Desktop, Cursor, or another MCP-compatible client to work with Chat.co, start with API vs MCP and MCP Agent Setup.
1.1 Key Features
| Feature | Description |
|---|---|
| RESTful API | Standard HTTP methods (GET, POST, DELETE) |
| Streaming Support | Real-time response streaming via SSE or plain text |
| Scoped API Keys | Keys can be restricted to specific chatbots for security |
| Citation Support | AI responses include source citations when available |
| Document Context | Attach uploaded documents to enhance AI responses |
1.2 Getting Started
To use the direct Chat.co API, you need to:
- Create a Chat.co account and set up a chatbot
- Generate an API key from your Settings page
- Assign the API key to a specific chatbot
- Use the API key in your application's requests
2. Authentication
Important: MCP uses a different onboarding flow than the direct API. Instead of manually creating a dashboard key and copying it into your client, MCP typically uses agent login with browser approval. See MCP Agent Setup.
2.1 Two kinds of key
Chat.co issues two key types, and choosing the wrong one is the most common security mistake teams make with this API.
sk_live_…Secret key
Full-power server-side credential. Carries whatever scopes you grant it, up to and including creating and deleting bots. Never ship one to a browser, a mobile app, or anything a user can read.
pk_live_…Publishable key
Browser-safe, bound to a single chatbot, and permanently locked to chat:read and chat:write — those scopes are forced at mint time and re-forced on every request. It can hold a conversation and nothing else.
Publishable keys are visible credentials. They are embedded in pages your visitors load, and their domain restriction is enforced from the Origin/Referer headers — which anything outside a browser can set freely. Treat a pk_live_ as public: fine for the embedded chat it was designed for, never a substitute for a secret key.
2.2 Scopes
Every secret key carries an explicit scope list. A request whose key lacks the required scope is rejected with 403, even if the key is otherwise valid and the chatbot is accessible — this is the single most common cause of a correct-looking request failing.
| Scope | Grants |
|---|---|
| chat:read | Read conversations and messages |
| chat:write | Create conversations and send messages |
| bot:read | Read chatbot details and configuration |
| bot:write | Create, update and delete chatbots; change configuration |
| content:read | Read Q&A pairs and text training |
| content:write | Create, update and delete Q&A pairs and text training |
| crawl:read | Read crawl jobs, crawled pages and document jobs |
| crawl:write | Start and cancel crawls; upload and delete documents |
| analytics:read | Read analytics, leads, knowledge gaps and message allocation |
A key created without an explicit scope list defaults to chat:read and chat:write only. Grant the narrowest set that does the job — a key that only reads analytics should not be able to delete a bot.
2.3 Authorization Header
Include your API key in the Authorization header of every request:
Authorization: Bearer sk_live_your_api_key_hereYou can also send the key without the Bearer prefix:
Authorization: sk_live_your_api_key_here2.4 Security Best Practices
Important: Never expose API keys in client-side code (JavaScript, mobile apps). Store keys in environment variables or secure vaults.
- Use chatbot-scoped keys when possible to limit access
- Set expiration dates for temporary integrations
- Rotate keys periodically
- Delete unused keys promptly
- Never commit API keys to version control
3. API Key Management
These endpoints require JWT authentication (your user session from the dashboard), not API key authentication.
3.1 Generate API Key
Creates a new API key for your account.
POST /api-keysRequest Body
{
"name": "My Integration Key",
"expiresAt": "2026-12-31T23:59:59Z",
"chatbotId": "507f1f77bcf86cd799439011"
}| Field | Type | Required | Description |
|---|---|---|---|
| name | string | No | User-friendly name (max 100 chars) |
| expiresAt | ISO 8601 date | No | Expiration date (must be in future) |
| chatbotId | string | No | Chatbot ID to scope the key |
Response (201 Created)
{
"success": true,
"message": "API key generated successfully...",
"data": {
"id": "507f1f77bcf86cd799439011",
"key": "sk_live_abcd1234efgh5678ijkl9012mnop3456qrst7890uvwx",
"keyPrefix": "sk_live_abcd1234efgh5678...",
"name": "My Integration Key",
"expiresAt": "2026-12-31T23:59:59.000Z",
"createdAt": "2025-11-10T12:00:00.000Z"
}
}Warning: The full key value is shown only once. Store it securely immediately.
3.2 List API Keys
GET /api-keys?page=1&limit=10Returns a paginated list of your API keys (prefixes only, not full keys).
3.3 Delete API Key
DELETE /api-keys/:idSoft-deletes an API key. The key will immediately become invalid.
4. Chat Endpoints
All Client API endpoints require API key authentication and are prefixed with /client/v1.
Important: Your API key must be associated with a chatbot. Keys without a chatbot assignment will receive a CHATBOT_ACCESS_DENIED error.
4.1 Get Chatbot Details
GET /client/v1/chatbotRetrieves the chatbot configuration and appearance settings associated with your API key.
Response
{
"success": true,
"data": {
"chatbot": {
"id": "507f1f77bcf86cd799439011",
"name": "Customer Support Bot",
"isPublic": true,
"appearance": {
"title": "Support Assistant",
"welcomeMessage": "Hello! How can I help you today?",
"placeholderText": "Type your question...",
"suggestions": [
{ "value": "What are your hours?" }
],
"enableDocumentUpload": true,
"showCitations": true
},
"createdAt": "2025-01-15T10:00:00.000Z"
}
}
}4.2 List Conversations
GET /client/v1/conversationsQuery Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 | Page number |
| limit | integer | 20 | Items per page (max 100) |
| sortBy | string | createdAt | createdAt or updatedAt |
| sortOrder | string | desc | asc or desc |
| startDate | ISO 8601 | - | Filter from this date |
| endDate | ISO 8601 | - | Filter until this date |
4.3 Create Conversation
POST /client/v1/conversationsRequest Body
{
"metadata": {
"source": "mobile-app",
"clientId": "user-12345"
}
}Response (201 Created)
{
"success": true,
"data": {
"conversation": {
"id": "507f1f77bcf86cd799439011",
"chatbotId": "507f1f77bcf86cd799439012",
"chatbot": {
"id": "507f1f77bcf86cd799439012",
"name": "Customer Support Bot"
},
"createdAt": "2025-11-10T10:00:00.000Z"
}
}
}4.4 Get Conversation
GET /client/v1/conversations/:conversationIdRetrieves a conversation with all its messages.
4.5 Send Message (Non-Streaming)
POST /client/v1/conversations/:conversationId/messagesRequest Body
{
"message": "What are your business hours?",
"documentIds": ["507f1f77bcf86cd799439015"]
}| Field | Type | Required | Description |
|---|---|---|---|
| message | string | Yes | Message content (max 8,000 chars) |
| documentIds | array | No | IDs of uploaded documents |
Response
{
"success": true,
"data": {
"userMessage": {
"id": "507f1f77bcf86cd799439016",
"content": "What are your business hours?",
"isFromUser": true,
"createdAt": "2025-11-10T10:16:00.000Z"
},
"botResponse": {
"id": "507f1f77bcf86cd799439017",
"content": "Our business hours are Monday through Friday, 9:00 AM to 5:00 PM EST.",
"isFromUser": false,
"createdAt": "2025-11-10T10:16:03.000Z",
"citations": [
{
"title": "Contact Information",
"url": "https://example.com/contact",
"snippet": "Hours of operation: Mon-Fri 9AM-5PM EST"
}
]
}
}
}4.6 Send Message (Streaming)
POST /client/v1/conversations/:conversationId/messages/streamSends a message and receives the AI response as a real-time stream. See Section 6 for streaming details.
5. Management API
The endpoints in Section 4 are the chat surface: they let a key already bound to one chatbot hold conversations. The Management API is everything else — creating bots, loading knowledge into them, and reading what comes back out. These routes are addressed by chatbot ID, so a single secret key can operate across every bot it has access to.
Secret keys only. Every route below requires a scope beyond chat:*, so a publishable key cannot reach any of them.
5.1 Chatbots
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /client/v1/chatbots | bot:read | List every chatbot this key can reach |
| GET | /client/v1/chatbots/:chatbotId | bot:read | Get one chatbot |
| POST | /client/v1/chatbots | bot:write | Create a chatbot |
| PATCH | /client/v1/chatbots/:chatbotId | bot:write | Rename, or change visibility |
| DELETE | /client/v1/chatbots/:chatbotId | bot:write | Soft-delete a chatbot |
5.2 Configuration
Paths below are relative to /client/v1/chatbots/:chatbotId.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /config | bot:read | Full sanitized configuration — never includes provider API keys |
| PATCH | /temperature | bot:write | Set response creativity |
| PATCH | /text-prompt | bot:write | Replace the system instruction prompt |
| PATCH | /appearance | bot:write | Widget appearance, voice and citation settings |
| PATCH | /domain | bot:write | Allowed embed domains and per-domain rate limits |
| GET | /whitelist | bot:read | Read email whitelist settings |
| POST | /whitelist/emails | bot:write | Add an email to the whitelist (private bots) |
| DELETE | /whitelist/emails | bot:write | Remove an email from the whitelist |
| PATCH | /whitelist | bot:write | Turn whitelist enforcement on or off |
5.3 Documents & crawling
Uploading is a three-step flow — presign, PUT the bytes straight to S3, then finalize. The file never transits the Chat.co API, which is what makes large uploads workable. Crawls pause after discovery so you choose which pages to keep.
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /documents | crawl:read | List uploaded document jobs |
| GET | /documents/check-existing | crawl:read | Check whether a file name was already uploaded |
| POST | /documents/presign-upload | crawl:write | Reserve storage, get a presigned S3 PUT URL |
| POST | /documents/finalize-upload | crawl:write | Turn a completed upload into a processing job |
| GET | /documents/:jobId | crawl:read | Processing status for one document |
| DELETE | /documents | crawl:write | Delete document jobs |
| POST | /crawl/jobs | crawl:write | Start a crawl |
| GET | /crawl/jobs | crawl:read | List crawl jobs |
| GET | /crawl/jobs/:jobId | crawl:read | Crawl job status |
| POST | /crawl/jobs/:jobId/cancel | crawl:write | Cancel a running crawl |
| GET | /crawl/jobs/:jobId/pages | crawl:read | Pages a crawl stored |
| GET | /crawl/jobs/:jobId/pending-pages | crawl:read | Discovered pages awaiting selection |
| POST | /crawl/jobs/:jobId/select-pages | crawl:write | Choose which discovered pages to index |
| POST | /crawl/jobs/:jobId/cancel-selection | crawl:write | Discard the pending pages |
5.4 Q&A and text training
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /qna | content:read | List Q&A pairs |
| POST | /qna | content:write | Create a Q&A pair |
| POST | /qna/bulk | content:write | Create many Q&A pairs in one call |
| GET | /qna/:qnaId | content:read | Get one Q&A pair |
| PATCH | /qna/:qnaId | content:write | Update a Q&A pair |
| DELETE | /qna/:qnaId | content:write | Delete a Q&A pair |
| GET | /text-training/status | content:read | Whether text training content exists |
| PUT | /text-training | content:write | Create or replace the text training body |
| DELETE | /text-training | content:write | Remove text training content |
5.5 Analytics, leads & knowledge gaps
| Method | Path | Scope | Description |
|---|---|---|---|
| GET | /client/v1/message-allocation | analytics:read | Remaining message credits for the key owner |
| POST | /client/v1/chatbots/:chatbotId/analytics | analytics:read | Analytics for one chatbot |
| GET | /client/v1/chatbots/:chatbotId/leads | analytics:read | Leads captured by one chatbot |
| GET | /client/v1/chatbots/:chatbotId/knowledge-gaps | analytics:read | Questions the bot could not answer |
| POST | /client/v1/chatbots/:chatbotId/knowledge-gaps/suggest-answer | analytics:read | Draft an answer for a detected gap |
| POST | /client/v1/chatbots/:chatbotId/knowledge-gaps/create-qna | content:write | Promote a gap straight into a Q&A pair |
Driving these endpoints from an AI client — Claude Desktop, Claude Code, Cursor — is usually easier through MCP than through raw HTTP. The Chat.co MCP server wraps this same surface as tools. See MCP Agent Setup and API vs MCP.
6. Streaming Responses
The streaming endpoint supports two formats via the format query parameter.
6.1 Plain Text Format (Default)
Best for simple integrations and testing with tools like Postman.
[START:507f1f77bcf86cd799439016]
Our return policy allows you to return most items within 30 days of purchase.
1. Items must be in original condition
2. You'll need the original receipt
[COMPLETE]
{"botMessageId":"507f1f77bcf86cd799439017","citations":[...]}| Marker | Description |
|---|---|
| [START:id] | Stream started, includes user message ID |
| <content> | Streamed response text (arrives incrementally) |
| [COMPLETE] | Stream finished successfully |
| [ERROR] | An error occurred during streaming |
6.2 Server-Sent Events (SSE) Format
Best for JavaScript applications using the EventSource API. Use ?format=sse.
data: {"type":"start","userMessageId":"507f1f77bcf86cd799439016"}
data: {"type":"content","content":"Our return policy"}
data: {"type":"content","content":" allows you to return"}
data: {"type":"complete","botMessageId":"507f1f77bcf86cd799439017","citations":[]}| Event Type | Fields | Description |
|---|---|---|
| start | userMessageId | Stream started |
| content | content | Text chunk to append |
| complete | botMessageId, citations | Stream finished |
| error | error | Error message |
7. Error Handling
7.1 Response Format
All API responses follow a consistent format:
Success Response
{
"success": true,
"data": { ... }
}Error Response
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable error description"
}
}7.2 Error Codes
| Code | HTTP Status | Description |
|---|---|---|
| INVALID_API_KEY | 401 | API key is missing, malformed, expired, or invalid |
| RATE_LIMIT_EXCEEDED | 401/429 | Too many failed attempts or message rate limit |
| CHATBOT_NOT_FOUND | 404 | Chatbot does not exist |
| CHATBOT_ACCESS_DENIED | 403 | API key not associated with chatbot |
| CHATBOT_FROZEN | 403 | Chatbot is frozen due to plan downgrade |
| CONVERSATION_NOT_FOUND | 404 | Conversation does not exist |
| CONVERSATION_ACCESS_DENIED | 403 | No access to this conversation |
| MESSAGE_LIMIT_EXCEEDED | 403 | Monthly message credit limit reached |
| INVALID_REQUEST | 400 | Request body validation failed |
| INTERNAL_ERROR | 500 | Unexpected server error |
8. Rate Limiting
8.1 Authentication Rate Limits
To protect against brute-force attacks, authentication is rate-limited:
| Limit | Value |
|---|---|
| Failed attempts | 5 per IP address |
| Lockout duration | 15 minutes |
8.2 Message Rate Limits
Message rate limits are based on your subscription plan. Exceeding your monthly message limit returns MESSAGE_LIMIT_EXCEEDED.
9. Code Examples
9.1 cURL Examples
Get Chatbot
curl -X GET "https://api.chat.co/client/v1/chatbot" \ -H "Authorization: Bearer sk_live_your_api_key"
Create Conversation
curl -X POST "https://api.chat.co/client/v1/conversations" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{}'Send Message
curl -X POST "https://api.chat.co/client/v1/conversations/CONVERSATION_ID/messages" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"message": "Hello, I need help"}'Stream Message
curl -X POST "https://api.chat.co/client/v1/conversations/CONVERSATION_ID/messages/stream?format=plain" \
-H "Authorization: Bearer sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"message": "Tell me about your products"}' \
--no-buffer9.2 Node.js Example
const axios = require('axios');
const API_KEY = 'sk_live_your_api_key';
const BASE_URL = 'https://api.chat.co/client/v1';
const client = axios.create({
baseURL: BASE_URL,
headers: {
'Authorization': `Bearer ${API_KEY}`,
'Content-Type': 'application/json'
}
});
async function chat() {
// 1. Create a new conversation
const { data: convResponse } = await client.post('/conversations');
const conversationId = convResponse.data.conversation.id;
console.log('Created conversation:', conversationId);
// 2. Send a message
const { data: msgResponse } = await client.post(
`/conversations/${conversationId}/messages`,
{ message: 'What services do you offer?' }
);
console.log('Bot response:', msgResponse.data.botResponse.content);
console.log('Citations:', msgResponse.data.botResponse.citations);
}
chat();9.3 Python Example
import requests
API_KEY = 'sk_live_your_api_key'
BASE_URL = 'https://api.chat.co/client/v1'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
# Create conversation
response = requests.post(f'{BASE_URL}/conversations', headers=headers, json={})
conversation_id = response.json()['data']['conversation']['id']
print(f'Created conversation: {conversation_id}')
# Send message
response = requests.post(
f'{BASE_URL}/conversations/{conversation_id}/messages',
headers=headers,
json={'message': 'What are your pricing plans?'}
)
result = response.json()
print(f"Bot: {result['data']['botResponse']['content']}")9.4 Python Streaming Example
import requests
API_KEY = 'sk_live_your_api_key'
BASE_URL = 'https://api.chat.co/client/v1'
headers = {
'Authorization': f'Bearer {API_KEY}',
'Content-Type': 'application/json'
}
conversation_id = 'your_conversation_id'
# Stream response
response = requests.post(
f'{BASE_URL}/conversations/{conversation_id}/messages/stream?format=plain',
headers=headers,
json={'message': 'Explain your features in detail'},
stream=True
)
for chunk in response.iter_content(chunk_size=None, decode_unicode=True):
if chunk:
print(chunk, end='', flush=True)Need Help?
If you have questions or need assistance with the API, our team is here to help.
Email: support@chat.co
© 2026 SA Cyber LLC d/b/a Chat.co. All rights reserved.
