This guide walks through integrating Boei's AI chatbot into a native mobile or game app with full support for human (live agent) takeover. You build the chat UI in your app, Boei handles the AI intelligence and routing to your live agents.
How to get there: Get your API key from your profile icon (top right) → API Keys.
Full API reference: Boei API or https://app.boei.help/docs/api
A conversation in Boei has 3 possible modes:
| Mode | What's happening |
|---|---|
ai |
The AI is responding. Each message you send gets an immediate AI reply. |
waiting_for_agent |
The user asked for a human. They're in queue, no agent assigned yet. |
live |
A human agent has joined and is replying. |
Your app's job:
POST /messages.ai mode, the reply comes back inline in the same response.waiting_for_agent or live mode, replies arrive asynchronously, so you poll GET /messages every few seconds to pick them up.POST /escalate.That's the whole flow.
Every request needs your API key in the Authorization header:
Authorization: Bearer YOUR_API_KEY
Get your API key from Settings → API in your Boei dashboard.
The chatbot UUID is the one shown on the bot's edit page (it appears in the URL).
POST /api/v1/chatbots/{chatbot_id}/messages
{
"message": "How do I deposit?",
"conversation_id": "550e8400-e29b-41d4-a716-446655440000",
"contact": { "name": "Vitória", "email": "[email protected]" }
}
conversation_id on the very first message. The response gives you back a new one. Store it locally and reuse it for every following message.contact is optional, but recommended so the agent sees who they're talking to.Response while in AI mode:
{
"message_id": "msg_001",
"conversation_id": "550e8400-e29b-41d4-a716-446655440000",
"response": "You can deposit via Pix or credit card from the Wallet screen.",
"sources": [...],
"usage": { "credits_used": 1, ... }
}
Response while in live/waiting mode:
{
"message_id": "msg_001",
"conversation_id": "550e8400-e29b-41d4-a716-446655440000",
"mode": "live",
"delivered": true
}
Notice there's no response field in live mode. That's how your app knows the message went to a human and the agent's reply will come in via polling.
GET /api/v1/chatbots/{chatbot_id}/conversations/{conversation_id}/messages?after_id=12345
after_id is the id of the last message you've already shown the user. On the first poll, use 0 (or omit it).
Response:
{
"conversation_id": "550e8400-e29b-41d4-a716-446655440000",
"mode": "live",
"waiting_for_agent": false,
"agent": { "name": "Sarah" },
"is_closed": false,
"messages": [
{
"id": 12346,
"role": "agent",
"sender_name": "Sarah",
"content": "Hi Vitória, I can help with that.",
"created_at": "2026-05-11T10:30:05Z"
}
],
"last_message_id": 12346
}
Use last_message_id as your after_id for the next poll.
Polling cadence:
is_closed: true, stop polling and show "Chat ended" in the UI.Roles you'll see in messages:
user – the visitor (your app user)assistant – the Boei AIagent – a human support repsystem – occasional system notes (rare, you can ignore or display in muted style)POST /api/v1/chatbots/{chatbot_id}/conversations/{conversation_id}/escalate
{
"reason": "User asked to speak with support"
}
reason is optional but helps agents triage.
Possible responses:
{ "status": "queued", "mode": "waiting_for_agent",
"message": "You're in the queue. An agent will join shortly." }
{ "status": "no_agents_available", "mode": "ai",
"message": "No agents are currently available. Please try again later." }
{ "status": "already_escalated", "mode": "live", ... }
After a successful escalation:
GET /messages if you weren't already.GET /api/v1/chatbots/{chatbot_id}/conversations/{conversation_id}
Use this when the user re-opens the app and you want to restore the full message history.
A simple, complete Cocos Creator chat screen needs three states.
┌─────────────────────────────────────────┐
│ Support [×] │
├─────────────────────────────────────────┤
│ │
│ [Bot] Hi! How can I help today? │
│ │
│ How do I deposit? [User] │
│ │
│ [Bot] You can deposit via Pix or │
│ credit card from the Wallet. │
│ │
│ │
├─────────────────────────────────────────┤
│ [Type a message...........] [Send] │
│ [ Talk to a human ] │
└─────────────────────────────────────────┘
After tapping "Talk to a human" (which calls POST /escalate):
┌─────────────────────────────────────────┐
│ Support [×] │
├─────────────────────────────────────────┤
│ │
│ [System] You're in the queue. An │
│ agent will join shortly. │
│ │
│ ⟳ Waiting for an agent... │
│ │
├─────────────────────────────────────────┤
│ [Type a message...........] [Send] │
└─────────────────────────────────────────┘
When the poll response returns agent: { name: "Sarah" }:
┌─────────────────────────────────────────┐
│ Sarah from Support [×] │
├─────────────────────────────────────────┤
│ │
│ [System] Sarah has joined the chat. │
│ │
│ [Sarah] Hi Vitória, I can help with │
│ that. │
│ │
├─────────────────────────────────────────┤
│ [Type a message...........] [Send] │
└─────────────────────────────────────────┘
When poll returns is_closed: true:
┌─────────────────────────────────────────┐
│ Support [×] │
├─────────────────────────────────────────┤
│ │
│ ...previous messages... │
│ │
│ ─── Chat ended ─── │
│ │
│ [ Start a new chat ] │
│ │
└─────────────────────────────────────────┘
conversation_id and start fresh).// State
let conversationId = null;
let lastMessageId = 0;
let mode = 'ai'; // 'ai' | 'waiting_for_agent' | 'live'
let pollHandle = null;
const HEADERS = {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
};
// 1. Send user message
async function sendMessage(text) {
const res = await fetch(`/api/v1/chatbots/${BOT_ID}/messages`, {
method: 'POST',
headers: HEADERS,
body: JSON.stringify({
message: text,
conversation_id: conversationId,
contact: { name: userName, email: userEmail },
}),
});
const data = await res.json();
conversationId = data.conversation_id;
appendBubble({ role: 'user', content: text });
if (data.response) {
// AI mode: reply is inline
appendBubble({ role: 'assistant', content: data.response });
} else {
// Live mode: agent reply will come via polling
mode = data.mode;
startPolling();
}
}
// 2. Escalate to human
async function requestLiveChat() {
const res = await fetch(
`/api/v1/chatbots/${BOT_ID}/conversations/${conversationId}/escalate`,
{ method: 'POST', headers: HEADERS, body: JSON.stringify({}) }
);
const data = await res.json();
mode = data.mode;
showSystemBubble(data.message);
if (data.status === 'queued') startPolling();
}
// 3. Poll loop
function startPolling() {
if (pollHandle) return;
pollHandle = setInterval(pollOnce, 4000);
}
function stopPolling() {
clearInterval(pollHandle);
pollHandle = null;
}
async function pollOnce() {
const url = `/api/v1/chatbots/${BOT_ID}/conversations/${conversationId}/messages?after_id=${lastMessageId}`;
const res = await fetch(url, { headers: HEADERS });
const data = await res.json();
mode = data.mode;
for (const msg of data.messages) {
appendBubble(msg);
lastMessageId = msg.id;
}
if (data.agent) setHeader(`${data.agent.name} from Support`);
if (data.is_closed) {
stopPolling();
showChatEnded();
}
}
conversation_id and lastMessageId in your app's local storage so the chat survives app restarts.agent field is only present once a human has been assigned. Don't show "Sarah is typing" speculatively, wait for the field.contact.email is highly recommended for iGaming. It links the chat to your customer record and lets agents send follow-up emails after the chat ends.is_closed: true, sending a new message will automatically reopen the conversation. But the cleaner UX is to start a fresh conversation_id.429, back off and retry after the time indicated in the Retry-After header.error and message fields and a non-2xx status code.# Send first message (no conversation_id)
curl -X POST https://app.boei.help/api/v1/chatbots/$BOT_ID/messages \
-H "Authorization: Bearer $API_KEY" \
-H "Content-Type: application/json" \
-d '{"message": "Hello"}'
# Escalate (use conversation_id from previous response)
curl -X POST https://app.boei.help/api/v1/chatbots/$BOT_ID/conversations/$CONV_ID/escalate \
-H "Authorization: Bearer $API_KEY"
# Poll for agent replies
curl https://app.boei.help/api/v1/chatbots/$BOT_ID/conversations/$CONV_ID/messages?after_id=0 \
-H "Authorization: Bearer $API_KEY"
If you run into trouble, contact [email protected] and we'll help you debug the integration.