# AI agent: behaviour & instructions
Source: https://guide.chatwize.ai/en/ai-agent
Decide how your chatbot answers: instructions, tone, model level and creativity.
The **knowledge base** decides *what* your chatbot talks about; the **AI agent**
decides *how* it does that.
## Where to find it
From **Chatbots**, click the chatbot you want to work on.
In the left sidebar, under **Main menu**, click **AI agent**.
## What you set
The standing brief for your bot: who it is, what it does and doesn't do, and
how it handles questions it can't answer.
Formal or informal, brief or expansive.
How capable the model is and how much context it carries. A higher level
reasons better about hard questions and costs more credits per message.
Lower = more factual and consistent. Higher = freer and more varied.
Be specific in your instructions about what the bot should do when it doesn't
know, for example refer to a person or ask for an email address. That stops it
from guessing.
## External lookups
On this page you also set whether your agent may call an **external service**
during a conversation, for example to fetch an order status. You specify which
addresses it's allowed to reach. The screen shows whether your current model
level supports it. How to set one up, field by field, is in
[Function calling](/en/function-calling).
Anything your agent may call, any visitor can indirectly cause it to call. So only
connect addresses that are safe for public use, and have the service itself check
whether the requested data belongs to this visitor.
## Multiple specialists
Do you have clearly different jobs (sales, support, billing)? Then you can create
**multiple agents** within one chatbot that route to each other. See
[Multiple agents](/en/multi-agent).
## Trying it out
Use **Test chatbot** in the sidebar to check your settings with real questions,
before you go live.
# Collecting data
Source: https://guide.chatwize.ai/en/data-collection
Capture names, email addresses and your own fields, and forward them.
Chatwize can collect information from conversations and forward it. You set this
up under **Settings**, in the **Collecting data** group.
## Where to find it
From **Chatbots**, click the chatbot you want to work on.
In the left sidebar, under **Manage**, click **Settings**.
Click **Contact form**, **Variables** or **Satisfaction / feedback** to
expand it.
## Three sections
Ask the visitor for details (name, email) with a form in the chat. You decide
the fields, whether they're required, and after how many messages it appears.
Decide which data the chatbot may collect (name, email, order number, …) and
where it goes.
Put thumbs under the AI's answers, with an optional comment from the visitor.
### Letting variables fill themselves
Per variable you can turn on that the assistant **recognises it itself** in the
conversation. If a visitor simply mentions their email address in a sentence,
it's captured without you having to show a form.
## Where the data goes
Everything collected sits in **Inbox → Data**, with a link back to the
conversation it came from. Form submissions and variables are shown together,
with a label showing where each entry came from. From that page you export
everything to CSV.
Automatic forwarding is set in the **Forwarding & integrations** group:
* **Email notifications** — a message to your own inbox.
* **Webhook** — data to your CRM, spreadsheet or automation tool.
See [Integrations](/en/integrations) for how to set those up.
Per channel you choose which fields are included. Tick one field and it's sent as
soon as that arrives; tick several and Chatwize waits until they're all there.
That choice applies to all webhooks together.
Collected data comes from what a visitor types. Treat it as untrusted input:
check it before you use it in your CRM, an invoice or a spreadsheet.
# Function calling
Source: https://guide.chatwize.ai/en/function-calling
Let your chatbot call your own API during a conversation.
Your knowledge base holds the rules. Function calling fetches the current state:
an order status, a stock level, a free slot. You give an address and say when
the bot should use it; Chatwize calls it during the conversation.
## Where to find it
From **Chatbots**, click your chatbot.
In the left sidebar, under **Main menu**. Open the agent that should get
this ability.
Under **Outbound API endpoints**, click **Add endpoint**.
## What you fill in
| Field | What to enter |
| - | - |
| **Slug** | Name for the AI, in `snake_case`: `lookup_order`. Fixed once created. |
| **Name** | Name for yourself. |
| **When should the bot call this?** | The most important field. What the API does and in which situation. |
| **Method** | `GET` to look something up. `POST`, `PUT` or `PATCH` if something changes. |
| **URL** | The full address, with `https://`. Publicly reachable. |
| **Allowlist host** | The hostname from the URL, exactly the same. |
| **Parameters** | JSON Schema of what the AI may fill in. Empty = no parameters. |
| **Action type** | **Read only** or **Performs an action (write)**. |
| **Automatic calling** | Write only. **On by default** — switch off while testing. |
| **Max. calls per conversation** | Brake against a bot that keeps calling. |
| **Headers** | Your own headers, such as `Authorization`. |
Write the description as an instruction: "Looks up an order by order number.
Call this when the visitor asks where their order is." Not: "Order API".
## Example
Order lookup on `https://api.example.com/orders`.
```json Parameters theme={null}
{
"type": "object",
"properties": {
"order_number": {
"type": "string",
"description": "The order number as the visitor states it, for example 10423"
}
},
"required": ["order_number"]
}
```
Chatwize calls `…/orders?order_number=10423`. You reply:
```json theme={null}
{ "status": "shipped", "carrier": "PostNL", "expected": "2026-09-25" }
```
The visitor reads: *"Your order is on its way with PostNL and expected on 25
September."*
**Stock** — "Returns the stock of one product. Call this when the visitor
asks whether something is in stock."
```json theme={null}
{
"type": "object",
"properties": {
"product_code": { "type": "string", "description": "The product code as shown on the site, for example AB-1234" }
},
"required": ["product_code"]
}
```
**Availability** — an `enum` keeps the bot within your categories.
```json theme={null}
{
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["compact", "family", "luxury"], "description": "The type the visitor asks about" },
"from": { "type": "string", "description": "Start date as YYYY-MM-DD" },
"until": { "type": "string", "description": "End date as YYYY-MM-DD" }
},
"required": ["category", "from", "until"]
}
```
A date arrives as text. Check it yourself.
**Callback request** — a write action via `POST`. Prevent duplicate
requests on your side.
```json theme={null}
{
"type": "object",
"properties": {
"name": { "type": "string", "description": "The name the visitor gives" },
"phone": { "type": "string", "description": "The phone number the visitor gives" }
},
"required": ["name", "phone"]
}
```
**No parameters** — `{}`. Opening hours, for example. The best endpoint to
start with.
WooCommerce: `https://yourstore.com/wp-json/wc/v3/orders` with parameter
`search`, and your consumer key and secret in an `Authorization` header.
Shopify and Magento work the same way: `GET` with query parameters, token in
a header.
Fixed values go in the URL yourself (`?per_page=1`); the AI cannot overwrite
those.
A read key sees **every** order — anyone who guesses an order number gets
its status. Put your own endpoint in front that requires order number and
email address and returns only a few fields.
## The schema
One flat object. Properties of type `string`, `number`, `integer` or `boolean`,
optionally with an `enum`. No nested objects or arrays. The `description` is
what the AI reads.
Everything in the schema can be influenced by what the visitor types. So this
never belongs in it:
| Never a parameter | Where it belongs |
| - | - |
| Key, token, password | Header |
| Customer, account or tenant ID | Fixed in the URL, or resolved by your own endpoint |
| `admin`, `debug` | Nowhere |
| `per_page` and other limits | Fixed in the URL |
A parameter `customer_id` gets filled with whatever the visitor says. Who gets
the data is decided by your own system — never by the conversation.
## What you receive
JSON over HTTPS, with your headers and a signature. Verify the signature: then
you know the request came from Chatwize and was not altered. You see the secret
once, when you create the endpoint.
Two headers: `X-Chatwize-Outbound-Timestamp` (moment of sending) and
`X-Chatwize-Outbound-Signature` (`sha256=` plus an HMAC-SHA256 over
`.`). The content is the raw body for `POST`, `PUT` and
`PATCH`, and the query string for `GET`.
```js Node.js theme={null}
import { createHmac, timingSafeEqual } from "node:crypto";
function isFromChatwize(secret, req, rawBody) {
const ts = req.headers["x-chatwize-outbound-timestamp"];
const received = req.headers["x-chatwize-outbound-signature"] ?? "";
if (!ts || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
const content = req.method === "GET" ? new URL(req.url, "https://x").search : rawBody;
const expected = "sha256=" + createHmac("sha256", secret)
.update(`${ts}.${content}`).digest("hex");
if (expected.length !== received.length) return false;
return timingSafeEqual(Buffer.from(expected), Buffer.from(received));
}
```
```python Python theme={null}
import hmac, hashlib, time
def is_from_chatwize(secret: str, headers, content: str) -> bool:
ts = headers.get("X-Chatwize-Outbound-Timestamp", "")
received = headers.get("X-Chatwize-Outbound-Signature", "")
if not ts or abs(time.time() - int(ts)) > 300:
return False
digest = hmac.new(secret.encode(), f"{ts}.{content}".encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(f"sha256={digest}", received)
```
```php PHP theme={null}
function isFromChatwize(string $secret, array $headers, string $content): bool {
$ts = $headers['X-Chatwize-Outbound-Timestamp'] ?? '';
$received = $headers['X-Chatwize-Outbound-Signature'] ?? '';
if ($ts === '' || abs(time() - (int) $ts) > 300) return false;
$expected = 'sha256=' . hash_hmac('sha256', "$ts.$content", $secret);
return hash_equals($expected, $received);
}
```
Sign over the raw body, compare with `timingSafeEqual` / `compare_digest` /
`hash_equals` (never `==`), and include the `?` for `GET`.
## What you send back
JSON, within five seconds, small. Only the start of a long response reaches
the AI. Anything you send can end up in the chat.
## Keep it safe
Anything your bot may call, any visitor can indirectly cause it to call.
* **Authorise on your side.** The signature proves it came from Chatwize, not
that this visitor is entitled to this data.
* **Prefer read over write.** Automatic calling off while testing.
* **Return as little as possible.**
* **Separate key in a header**, with as few rights as possible.
* **Public address that answers directly.** Internal addresses and redirects do
not work.
## When it does not work
| What you see | Usually |
| - | - |
| Bot never calls it | The description. Write out the situation in the visitor's words. Is the endpoint on, and on the right agent? |
| Call never leaves | URL host and allowlist host are not exactly the same. |
| Verification keeps failing | Wrong bytes: parsed body, or query string without the `?`. |
| Timeout | Your API is too slow. Cache the answer on your side. |
| Write action does not happen | Automatic calling is off. |
| Parameters refused | Does not match your schema. Sharpen the descriptions. |
Every call is in the inbox: which endpoint, which parameters, what came back.
# How it works
Source: https://guide.chatwize.ai/en/how-it-works
Finding your way in the dashboard: where everything lives.
This is the one thing to learn once; after that you can find every feature.
## The left sidebar
When you open a chatbot, everything for that chatbot sits in the **left
sidebar**, split into three groups:
| Group | What's in it |
| - | - |
| **Main menu** | **Dashboard** (statistics), **Inbox** (conversations and collected data), **Sources** (its knowledge), **AI agent** (behaviour) |
| **Manage** | **Settings** (the widget and its behaviour), **Team** (people and their permissions) |
| **Publish** | **Test chatbot** (try it out), **Go live** (put it on your site) |
Parts your account has no permission for aren't shown in the menu and can't be
opened either. **Team** is admins only. At the bottom of the sidebar you'll find
your usage and the NL/EN language switch; your workspace sits in the top right.
## The Settings page
Most things you want to change live under **Settings**. That page is a list of
**sections** you click to expand. Changing a setting is always two steps:
**open Settings → open the right section.**
The sections are bundled into six groups:
| Group | What for |
| - | - |
| **Appearance** | Colors, size, greeting, avatar, example questions, input field, footer, chat button, greeting bubble |
| **Conversation** | Citations & copying, disclaimer |
| **Access & management** | Password protection, rate limit, handover to a person, labels |
| **Collecting data** | Contact form, variables, satisfaction & feedback |
| **Forwarding & integrations** | Webhook, email notifications |
| **Danger zone** | Delete chatbot |
On the right is a **live preview** of the widget, so you see every change as you
make it. At the bottom a bar appears to save or discard your changes.
Say you want visitors to be able to reach a person:
In the left sidebar, under **Manage**, click **Settings**.
Scroll to the **Access & management** group and click **Handover to a
person** to expand it.
Every feature page in this guide starts with a **"Where to find it"** list.
## How an answer is produced
For every question, Chatwize first looks up the relevant passages in your own
sources and writes the answer from those. So the chatbot answers from your
content, and can show the source alongside.
Clear, well-structured pages produce clear answers. See
[Knowledge base](/en/knowledge-base).
Next: build one in the [Quickstart](/en/quickstart).
# Handover to a person
Source: https://guide.chatwize.ai/en/human-handover
Let visitors reach a real person, with optional office hours.
Visitors can ask to talk to your team; you get a notification and can take the
conversation over. You turn this on under **Settings**, in the **Access &
management** group.
## Where to find it
From **Chatbots**, click the chatbot you want to work on.
In the left sidebar, under **Manage**, click **Settings**.
Scroll to the **Access & management** group and click **Handover to a
person** to expand it.
## What you set
**Allow handover** turns the whole feature on or off. With it off there is no
button, no notifications, and you cannot take over a conversation yourself
either.
What the visitor sees when they ask for a person, and the notices when a
colleague joins or leaves the conversation.
The button a visitor uses to ask for a person. You set the text yourself; by
default it reads "Talk to a human". You also choose whether the button sits
separately below the suggested questions or among them.
Optional: only hand over during office hours. You set a **time zone** and,
per day (Monday to Sunday), whether you are open and between which times.
## Outside office hours
Outside your opening times there is no live handover; the visitor sees your
**offline message** instead. The question is still recorded and your
notifications still go out, so your team can follow up later.
Office hours can only *limit* when handover is offered; they never turn it on if
the main switch is off.
## Taking over a conversation
In the left sidebar, click **Inbox**. Conversations where someone is waiting
are marked.
Open the conversation and click **Take over the conversation**. At the top
you will see "Live chat active - you're answering now"; the AI is paused
while you are handling the conversation.
Done? Click **Hand back to AI** and the assistant picks it up again.
## Notifications
While you have the Inbox open, you get a **sound and a notification** when a
visitor asks for a person. To hear about it outside the dashboard too, turn on an
email notification or a webhook. See [Integrations](/en/integrations).
# Install on your site
Source: https://guide.chatwize.ai/en/installation
Add the chat widget to any website with one snippet.
Putting your chatbot on your website is one script tag. You get it from the
**Go live** page.
## Where to find it
From **Chatbots**, click the chatbot you want to publish.
In the left sidebar, under **Publish**, click **Go live**.
Click **On your website**, enter your website address and click **Generate
code**. Your embed code appears; copy it.
## Your code
The code looks like this, with your own key in place of
`wk_YOUR_WIDGET_KEY`:
```html theme={null}
```
Use the code exactly as you receive it. The widget key belongs to the website
address you entered. To show the chatbot on a second domain, add that address on
the **Go live** page.
## Where to paste it
Paste the code just before the closing `