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

  1. POST the user's message and your chatbotId to /api/chat.
  2. Read the reply from the JSON body. Read the X-Chat-Session-Id response header — that's your session ID.
  3. For the next message, send the same session ID in the X-Chat-Session-Id request header. The server now has conversation context (history, RAG, live-chat state).
  4. 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

HeaderRequiredDescription
Content-TypeYesMust be application/json.
X-Chat-Session-IdNoSession ID for conversation continuity. Omit on the first request; the response header returns a new one.

Request Body

FieldTypeRequiredDescription
messagestringYesThe user's message. Maximum 700 characters. Cannot be empty.
chatbotIdstring (UUID)YesYour chatbot's ID, from the chatbot settings.
pageUrlstringNoThe 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.

FieldTypeDescription
replystringThe AI-generated answer. May contain HTML formatting.
sourcesarraySources the answer was grounded in (see below). Empty if none were used.
modestringConversation mode: bot (AI is answering) or human (a live agent has taken over). Present when relevant.
statusstringLive 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:

FieldTypeDescription
typestringweb (a website page) or product (structured product data).
sourcestringFor web: the page URL. For product: the product identifier.
dataobjectOnly 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

ParameterTypeRequiredDescription
chatbotIdstring (UUID)YesYour chatbot's ID.
sessionIdstring (UUID)YesThe 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

ParameterTypeRequiredDescription
chatbotIdstring (UUID)YesYour chatbot's ID.
sessionIdsstringYesComma-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

HeaderRequiredDescription
X-Chat-Session-IdYesThe 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.

StatusMeaning
400Invalid body, missing field, empty message, or message over 700 characters.
403Domain not allowed, wiki authentication failed, or a plan restriction applies.
404Chatbot not found.
429Rate limit hit, or the monthly message quota is reached.
502The 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

ScopeLimit
Per session10 requests per minute
Per IP address15 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);