REST API
Send a message to your chatbot and get an AI-generated reply over plain HTTP. Use this to build a custom chat UI, a mobile app, or a backend automation. Every endpoint is served from the same origin as your widget script (https://app.webchatagent.com).
How a conversation works
- POST the user's
messageand yourchatbotIdto/api/chat. - Read the
replyfrom the JSON body. Read theX-Chat-Session-Idresponse header — that's your session ID. - For the next message, send the same session ID in the
X-Chat-Session-Idrequest header. The server now has conversation context (history, RAG, live-chat state). - Repeat. Omit the header any time you want to start a fresh conversation.
The server tracks history per session, so you only ever send the latest message — never the full transcript.
Authentication
The API uses domain-based authentication: there is no API key. Each request is checked against the chatbot's configured Allowed Domains using the Origin/Referer of the request. A request from a domain that isn't allowed gets a 403.
For AI Team Wiki chatbots with protected access, also send the X-Wiki-Auth header with the wiki's authentication token (the value is wiki_auth_<subdomain>). Without it, protected wikis return 403.
Send a Message
POST https://app.webchatagent.com/api/chat
Headers
| Header | Required | Description |
|---|---|---|
Content-Type | Yes | Must be application/json. |
X-Chat-Session-Id | No | Session ID for conversation continuity. Omit on the first request; the response header returns a new one. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
message | string | Yes | The user's message. Maximum 700 characters. Cannot be empty. |
chatbotId | string (UUID) | Yes | Your chatbot's ID, from the chatbot settings. |
pageUrl | string | No | The full page URL the visitor is on (window.location.href). Used for page-aware retrieval; validated against your allowed domains. |
Example Request
{
"message": "What are your business hours?",
"chatbotId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}
Response
The session ID is returned in the X-Chat-Session-Id response header, not in the body.
| Field | Type | Description |
|---|---|---|
reply | string | The AI-generated answer. May contain HTML formatting. |
sources | array | Sources the answer was grounded in (see below). Empty if none were used. |
mode | string | Conversation mode: bot (AI is answering) or human (a live agent has taken over). Present when relevant. |
status | string | Live chat status: waiting, open, or closed. Only present when Live Chat is active for the session. |
When a human agent has taken over (mode: "human", status: "open"), the reply may be empty — the agent answers separately. While a takeover is waiting, the reply is a short notice like "A team member will join shortly."
Sources Array
Each source object:
| Field | Type | Description |
|---|---|---|
type | string | web (a website page) or product (structured product data). |
source | string | For web: the page URL. For product: the product identifier. |
data | object | Only for product. Contains id, dataType, format, data, and sourceUrl. |
Example Response
{
"reply": "Our business hours are Monday to Friday, 9 AM to 5 PM CET.",
"sources": [
{
"type": "web",
"source": "https://example.com/contact"
}
],
"mode": "bot"
}
Streaming: If a chatbot has streaming enabled, the widget receives the reply token-by-token over Server-Sent Events. The plain JSON response documented here is what you get for a standard request and is the right model for server-to-server and most custom-UI integrations.
Chat History
Fetch the stored messages for a session (for example to restore a conversation after a page reload). History older than 30 days is removed for GDPR; an expired session returns 410.
GET https://app.webchatagent.com/api/chat/history
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
chatbotId | string (UUID) | Yes | Your chatbot's ID. |
sessionId | string (UUID) | Yes | The session whose history you want. |
Response
messages is ordered oldest-first. sender is bot or user (it is a display value, not the raw role). role is the underlying user / assistant / system role, and isAgent is true when an assistant message came from a human agent rather than the AI.
{
"messages": [
{
"id": 123,
"sender": "user",
"role": "user",
"isAgent": false,
"text": "What are your hours?",
"createdAt": "2025-01-15T10:30:00Z"
},
{
"id": 124,
"sender": "bot",
"role": "assistant",
"isAgent": false,
"text": "Our hours are Monday to Friday, 9 AM to 5 PM.",
"sources": [{ "type": "web", "source": "https://example.com/contact" }],
"createdAt": "2025-01-15T10:30:01Z"
}
]
}
sources is present only when a message has them.
Session Info
Get message counts and last activity for sessions known to this browser. To avoid leaking other visitors' chats, you must pass the session IDs you already hold (e.g. from local storage). Sessions with no activity in the last 30 days are not returned.
GET https://app.webchatagent.com/api/chat/sessions
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
chatbotId | string (UUID) | Yes | Your chatbot's ID. |
sessionIds | string | Yes | Comma-separated session UUIDs (max 5; extras are ignored). |
Response
{
"sessions": [
{
"sessionId": "b2c3d4e5-f6a7-8901-bcde-f23456789012",
"messageCount": 12,
"lastActivity": "2025-01-15T10:35:00Z"
}
]
}
Reset Session History
Clear the in-memory conversation context for a session so the next message starts the AI fresh (no prior turns). This does not delete stored messages — conversation_messages are business data and stay in the database (and in /api/chat/history).
DELETE https://app.webchatagent.com/api/chat/session
Headers
| Header | Required | Description |
|---|---|---|
X-Chat-Session-Id | Yes | The session whose in-memory history to clear. |
Response
{ "success": true, "message": "Chat session cleared." }
Error Handling
Errors from /api/chat return the same shape as a normal reply: a user-friendly HTML message in reply and an empty sources array. The HTTP status code carries the actual error type.
| Status | Meaning |
|---|---|
400 | Invalid body, missing field, empty message, or message over 700 characters. |
403 | Domain not allowed, wiki authentication failed, or a plan restriction applies. |
404 | Chatbot not found. |
429 | Rate limit hit, or the monthly message quota is reached. |
502 | The AI provider (LLM) returned an error. |
Error Response Body
{
"reply": "<p>I'm getting a lot of requests right now. Please try again in a few moments.</p>",
"sources": []
}
The body is always { reply, sources } — there is no separate error envelope. Branch on the HTTP status code, and show reply to the user if you want a ready-made message.
Rate Limiting
| Scope | Limit |
|---|---|
| Per session | 10 requests per minute |
| Per IP address | 15 requests per minute |
Exceeding either returns 429. Separately, hitting the plan's monthly message quota also returns 429 (with a "temporarily unavailable" message).
Code Examples
cURL
# Send a message (capture the session id from the response header)
curl -i -X POST https://app.webchatagent.com/api/chat \
-H "Content-Type: application/json" \
-d '{
"message": "What products do you offer?",
"chatbotId": "YOUR_CHATBOT_ID"
}'
# Continue the conversation (reuse the session id from above)
curl -X POST https://app.webchatagent.com/api/chat \
-H "Content-Type: application/json" \
-H "X-Chat-Session-Id: SESSION_ID_FROM_FIRST_RESPONSE" \
-d '{
"message": "Tell me more about the premium plan",
"chatbotId": "YOUR_CHATBOT_ID"
}'
JavaScript / TypeScript
async function chat(message, chatbotId, sessionId = null) {
const headers = { 'Content-Type': 'application/json' };
if (sessionId) headers['X-Chat-Session-Id'] = sessionId;
const response = await fetch('https://app.webchatagent.com/api/chat', {
method: 'POST',
headers,
body: JSON.stringify({ message, chatbotId })
});
const data = await response.json();
// The session id lives in the response header — keep it for follow-up messages.
const newSessionId = response.headers.get('X-Chat-Session-Id');
return { ...data, sessionId: newSessionId || sessionId };
}
// First message
const result = await chat('Hello!', 'YOUR_CHATBOT_ID');
console.log(result.reply);
// Follow-up in the same conversation
const followUp = await chat('Tell me more', 'YOUR_CHATBOT_ID', result.sessionId);
console.log(followUp.reply);
Python
import requests
CHATBOT_ID = "YOUR_CHATBOT_ID"
URL = "https://app.webchatagent.com/api/chat"
# First message
response = requests.post(URL, json={
"message": "What are your business hours?",
"chatbotId": CHATBOT_ID,
})
data = response.json()
session_id = response.headers.get("X-Chat-Session-Id")
print("Reply:", data["reply"])
print("Sources:", data["sources"])
# Continue the conversation
response = requests.post(
URL,
json={"message": "And on weekends?", "chatbotId": CHATBOT_ID},
headers={"X-Chat-Session-Id": session_id},
)
print("Reply:", response.json()["reply"])
PHP
<?php
$chatbotId = 'YOUR_CHATBOT_ID';
$url = 'https://app.webchatagent.com/api/chat';
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'message' => 'What are your business hours?',
'chatbotId' => $chatbotId,
]),
CURLOPT_HEADER => true, // include headers so we can read the session id
]);
$response = curl_exec($ch);
$headerSize = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$headers = substr($response, 0, $headerSize);
$body = json_decode(substr($response, $headerSize), true);
echo 'Reply: ' . $body['reply'] . PHP_EOL;
// Pull the session id from the response headers for follow-up messages
preg_match('/X-Chat-Session-Id:\s*(.+)/i', $headers, $matches);
$sessionId = trim($matches[1] ?? '');
curl_close($ch);
