AI assistant
An AI agent that answers your visitors from your knowledge base, with your own Claude or OpenAI key, and hands the chat to your team when a person is needed.
Set it up
- In the dashboard, open AI → Assistant, choose Claude or OpenAI, paste your API key and press Save & test. ZebChat lists the models your key can use and suggests one.
- Add your help center, documents and FAQs under AI → Knowledge. The knowledge base needs an OpenAI or Voyage AI key for embeddings (Claude has no embeddings API).
- On the AI agent tab, give the assistant a name, an avatar and instructions, then choose when it answers.
- Try it in the Playground: it uses your key and knowledge, shows the sources it used and what each answer cost, and never reaches a visitor.
- Turn the assistant on.
When it answers
- Answers first: the AI answers every new chat. Your team gets the chat when the AI hands it over, or when an agent presses Take over.
- Only when nobody is available: outside business hours or when every agent is away. As soon as an agent is available, the chat goes to them.
- Off: visitors only talk to your team.
Visitors see the assistant’s name with an “AI” badge, and its replies appear word by word as they are written.
Handing off to people
The AI hands the chat to your team, with a summary as an internal note, when:
- the visitor asks for a person or seems upset, or needs something the AI can’t do
- a visitor message contains one of your handoff keywords (for example “refund”)
- it reached your limit of AI replies for one chat
- your monthly spend cap is reached, or your provider refuses the key
Once a person replies or takes the chat, the AI stays out of that conversation. Agents see a line such as “Zeb handed the chat to the team” in the thread.
Actions
Actions let the assistant look things up or do things in your own systems, such as checking an order or a delivery. You define each one under AI → Actions: a tool name (check_order), a description that tells the AI when to call it, the fields it fills in (name, type, description, required, allowed values), and your HTTPS endpoint. Only enabled actions are offered, optionally on some websites only. The AI never gets direct access to anything: it can only ask ZebChat to call your endpoint, and ZebChat checks the fields first.
- Confirmation: for actions that change something (cancel, rebook), turn on Ask the visitor to confirm first. The AI describes what it will do, and the visitor gets Confirm and Cancel buttons (or answers yes or no). Nothing is sent until they confirm.
- Send test request calls your endpoint with sample fields and
"test": true, and shows the response and what the AI would see. - Every call is in the call log (arguments, response, status, time) for 30 days. Calls are limited to 10 per chat per hour and 60 per minute for your organization.
The request
ZebChat sends a POST with a JSON body to your endpoint, signed like webhooks. conversation and visitor are null for test requests, playground and test-question calls. The visitor’s name, email and externalId are only sent when your website verified them with ZebChat.setUser and a hash; never trust identity from a request where verified is false.
POST /zebchat/actions HTTP/1.1
Content-Type: application/json
User-Agent: ZebChat-Actions/1.0
ZebChat-Event: ai.action
ZebChat-Delivery: acl_0199…
ZebChat-Signature: t=1791158400,v1=5f8c0e…
{
"id": "acl_0199…",
"action": "check_order",
"arguments": { "order_number": "A-1042" },
"organizationId": "org_0199…",
"conversation": { "id": "conv_0199…" },
"visitor": {
"id": "vis_0199…",
"verified": true,
"name": "Vera",
"email": "[email protected]",
"externalId": "user_42"
},
"test": false,
"createdAt": "2026-10-05T10:00:00.000Z"
}Your response
Answer within 10 seconds with a 2xx status and JSON (up to 16 KB is read; the AI sees the first 4,000 characters). Return only what the visitor may know: the AI treats it as data, never as instructions, and answers from it. Anything else (an error status, a timeout, a redirect) is reported to the AI as a failure, and it tells the visitor it couldn’t complete the request instead of guessing.
HTTP/1.1 200 OK
Content-Type: application/json
{ "order": "A-1042", "status": "shipped", "carrier": "DHL", "eta": "2026-10-08" }Verifying the signature
ZebChat-Signature: t=…,v1=… holds a Unix timestamp and the hex HMAC-SHA256 of {t}.{raw body} with the action’s signing secret (shown once when you create the action or rotate the secret). Compute it over the raw body, compare in constant time, and reject timestamps older than five minutes.
import { createHmac, timingSafeEqual } from 'node:crypto';
import { createServer } from 'node:http';
const SECRET = process.env.ZEBCHAT_ACTION_SECRET; // whsec_…, shown when you created the action
function verify(header, rawBody) {
const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
const age = Math.abs(Date.now() / 1000 - Number(parts.t));
if (!parts.t || !parts.v1 || age > 300) return false; // reject replays older than 5 minutes
const expected = createHmac('sha256', SECRET).update(`${parts.t}.${rawBody}`).digest();
const actual = Buffer.from(parts.v1, 'hex');
return actual.length === expected.length && timingSafeEqual(actual, expected);
}
createServer((req, res) => {
let raw = '';
req.on('data', (chunk) => (raw += chunk));
req.on('end', () => {
if (!verify(req.headers['zebchat-signature'] ?? '', raw)) return res.writeHead(401).end();
const call = JSON.parse(raw);
if (call.action === 'check_order') {
// visitor.email and visitor.externalId are only present when visitor.verified is true.
const order = { order: call.arguments.order_number, status: 'shipped', eta: '2026-10-08' };
return res.writeHead(200, { 'Content-Type': 'application/json' }).end(JSON.stringify(order));
}
res.writeHead(404).end();
});
}).listen(8080);Reports and test questions
- AI → Reports shows the chats the AI handled, how many it resolved without a handoff, the handoff rate and reasons, replies, tokens and estimated cost per day, the average reply time, the knowledge sources used most, action calls with their success rate, and your team’s feedback.
- In the inbox, agents rate AI replies with 👍 or 👎 and an optional note.
- AI → Test questions: save questions with the answer you expect, then run them after changing instructions or knowledge. Each answer is graded by the same model for the key facts. A run uses your own key, so ZebChat shows a cost estimate and asks you to confirm first.
Costs and limits
ZebChat estimates the cost of every answer from its tokens and your model’s list price, and shows it per month in the dashboard. Set an optional monthly spend cap: when it is reached, the AI hands every chat to your team until next month. Your provider’s invoice is what you pay.
Your data
Your key is stored encrypted and is never shown again, not even to ZebChat staff. For each answer the provider receives the assistant’s instructions, the recent messages of that chat (no internal notes or visitor profile), and a few passages from your knowledge base. Knowledge and action results are treated as data, never as instructions. Your action endpoints receive only the fields the AI filled in, the conversation and visitor ids, and the visitor’s identity only when your website verified it. See Security and data handling.