Adicione um chat ao vivo no seu site em poucos minutos
Para integrar o webchat, você precisará das seguintes informações da sua conexão:
| Campo | Descrição | Onde encontrar |
|---|---|---|
connectionToken | Token UUID da conexão webchat | Dashboard → Conexões |
apiKey | Chave de autenticação | Fornecida ao criar a conexão |
Acesse o dashboard, vá em Conexões e crie uma nova conexão do tipo webchat. Anote o
token e a webchatApiKey.
Copie e cole o código abaixo antes do fechamento da tag </body>:
<!-- Webchat Widget -->
<script>
(function() {
// ⚠️ CONFIGURE AQUI
const WEBCHAT_CONFIG = {
connectionToken: 'SEU_CONNECTION_TOKEN',
apiKey: 'SUA_API_KEY',
apiUrl: 'https://sua-api.com.br'
};
// Criar botão flutuante
const btn = document.createElement('div');
btn.id = 'webchat-btn';
btn.innerHTML = '💬';
btn.style.cssText = 'position:fixed;bottom:20px;right:20px;width:60px;height:60px;background:#4F46E5;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:28px;cursor:pointer;box-shadow:0 4px 20px rgba(79,70,229,0.4);z-index:9999;transition:transform 0.2s';
btn.onmouseover = () => btn.style.transform = 'scale(1.1)';
btn.onmouseout = () => btn.style.transform = 'scale(1)';
document.body.appendChild(btn);
// Criar modal do chat
const modal = document.createElement('div');
modal.id = 'webchat-modal';
modal.style.cssText = 'display:none;position:fixed;bottom:90px;right:20px;width:380px;max-height:600px;background:#1E293B;border-radius:16px;box-shadow:0 10px 40px rgba(0,0,0,0.3);z-index:9999;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;display:flex;flex-direction:column';
modal.innerHTML = `
<div style="background:#4F46E5;padding:16px;color:white;flex-shrink:0">
<h3 style="margin:0;font-size:18px">💬 Atendimento</h3>
<p style="margin:4px 0 0;font-size:13px;opacity:0.9">Preencha seus dados para iniciar</p>
</div>
<form id="webchat-form" style="padding:20px;flex-shrink:0">
<div style="margin-bottom:12px">
<label style="display:block;font-size:13px;color:#94A3B8;margin-bottom:4px">Seu nome *</label>
<input type="text" id="webchat-name" required style="width:100%;padding:10px 12px;border:1px solid #334155;border-radius:8px;background:#0F172A;color:white;font-size:14px" placeholder="Digite seu nome">
</div>
<div style="margin-bottom:12px">
<label style="display:block;font-size:13px;color:#94A3B8;margin-bottom:4px">WhatsApp *</label>
<input type="tel" id="webchat-whatsapp" required style="width:100%;padding:10px 12px;border:1px solid #334155;border-radius:8px;background:#0F172A;color:white;font-size:14px" placeholder="(11) 99999-9999">
</div>
<div style="margin-bottom:12px">
<div style="background:#0F172A;border:1px solid #334155;border-radius:8px;padding:10px 12px;color:#94A3B8;font-size:12px;line-height:1.4">
Ao informar seu número de WhatsApp, você autoriza a empresa a entrar em contato por este canal.
</div>
</div>
<div style="margin-bottom:16px">
<label style="display:block;font-size:13px;color:#94A3B8;margin-bottom:4px">Mensagem *</label>
<textarea id="webchat-message" required rows="3" style="width:100%;padding:10px 12px;border:1px solid #334155;border-radius:8px;background:#0F172A;color:white;font-size:14px;resize:none" placeholder="Como podemos ajudar?"></textarea>
</div>
<button type="submit" style="width:100%;padding:12px;background:#4F46E5;color:white;border:none;border-radius:8px;font-size:14px;font-weight:600;cursor:pointer">Enviar mensagem</button>
</form>
<div id="webchat-chat" style="display:none;flex-direction:column;flex:1;overflow:hidden">
<div id="webchat-chat-messages" style="flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px"></div>
<div style="padding:12px;border-top:1px solid #334155;flex-shrink:0">
<div style="display:flex;gap:8px">
<input type="text" id="webchat-chat-input" placeholder="Digite sua mensagem..." style="flex:1;padding:10px 12px;border:1px solid #334155;border-radius:8px;background:#0F172A;color:white;font-size:14px">
<button id="webchat-chat-send" style="padding:10px 20px;background:#4F46E5;color:white;border:none;border-radius:8px;cursor:pointer">Enviar</button>
</div>
</div>
</div>
<div id="webchat-success" style="display:none;padding:40px 20px;text-align:center">
<div style="font-size:48px;margin-bottom:12px">✅</div>
<h3 style="color:white;margin:0 0 8px">Mensagem enviada!</h3>
<p style="color:#94A3B8;font-size:14px">Em breve entraremos em contato.</p>
</div>
`;
document.body.appendChild(modal);
// Toggle modal
btn.onclick = () => {
modal.style.display = modal.style.display === 'none' ? 'block' : 'none';
};
let visitorId = localStorage.getItem('webchat_visitor') || null;
let lastMessageId = 0;
let pollingInterval = null;
// Função para buscar mensagens recebidas
async function fetchMessages() {
if (!visitorId) return;
try {
const res = await fetch(`${WEBCHAT_CONFIG.apiUrl}/api/webchat/messages/${WEBCHAT_CONFIG.connectionToken}/${visitorId}?lastMessageId=${lastMessageId}`, {
headers: {
'x-api-key': WEBCHAT_CONFIG.apiKey
}
});
if (res.ok) {
const data = await res.json();
if (data.success && data.messages && data.messages.length > 0) {
const chatMessages = document.getElementById('webchat-chat-messages');
data.messages.forEach(msg => {
const id = Number(msg.id);
if (Number.isInteger(id) && id > 0 && id <= 1e12 && id > lastMessageId) {
lastMessageId = id;
}
// Adicionar mensagem recebida
const msgDiv = document.createElement('div');
msgDiv.style.cssText = 'background:#334155;padding:10px 12px;border-radius:8px;max-width:80%;align-self:flex-start';
msgDiv.innerHTML = `<div style="color:white;font-size:14px">${msg.text || ''}</div>`;
chatMessages.appendChild(msgDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
});
}
}
} catch (err) {
console.error('Erro ao buscar mensagens:', err);
}
}
// Iniciar polling de mensagens (carrega histórico primeiro, depois poll a cada 3s)
async function startPolling() {
if (pollingInterval) clearInterval(pollingInterval);
lastMessageId = 0;
await fetchMessages();
pollingInterval = setInterval(fetchMessages, 3000);
}
// Parar polling
function stopPolling() {
if (pollingInterval) {
clearInterval(pollingInterval);
pollingInterval = null;
}
}
// Enviar mensagem inicial
document.getElementById('webchat-form').onsubmit = async (e) => {
e.preventDefault();
const name = document.getElementById('webchat-name').value;
const whatsapp = document.getElementById('webchat-whatsapp').value;
const message = document.getElementById('webchat-message').value;
if (!visitorId) {
visitorId = 'visitor_' + Date.now() + '_' + Math.random().toString(36).substring(2, 9);
localStorage.setItem('webchat_visitor', visitorId);
}
try {
const res = await fetch(`${WEBCHAT_CONFIG.apiUrl}/api/webhook/webchat/${WEBCHAT_CONFIG.connectionToken}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': WEBCHAT_CONFIG.apiKey
},
body: JSON.stringify({ visitorId, visitorName: name, whatsapp, message })
});
if (res.ok) {
// Salvar dados no localStorage
localStorage.setItem('webchat_name', name);
localStorage.setItem('webchat_whatsapp', whatsapp);
// Esconder formulário inicial e mostrar chat
document.getElementById('webchat-form').style.display = 'none';
document.getElementById('webchat-chat').style.display = 'flex';
// Adicionar mensagem enviada
const chatMessages = document.getElementById('webchat-chat-messages');
const msgDiv = document.createElement('div');
msgDiv.style.cssText = 'background:#4F46E5;padding:10px 12px;border-radius:8px;max-width:80%;align-self:flex-end';
msgDiv.innerHTML = `<div style="color:white;font-size:14px">${message}</div>`;
chatMessages.appendChild(msgDiv);
// Iniciar polling
startPolling();
}
} catch (err) {
alert('Erro ao enviar mensagem');
}
};
// Enviar mensagem no chat
document.getElementById('webchat-chat-send').onclick = async () => {
const input = document.getElementById('webchat-chat-input');
const message = input.value.trim();
if (!message || !visitorId) return;
try {
const res = await fetch(`${WEBCHAT_CONFIG.apiUrl}/api/webhook/webchat/${WEBCHAT_CONFIG.connectionToken}`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'x-api-key': WEBCHAT_CONFIG.apiKey
},
body: JSON.stringify({
visitorId,
visitorName: localStorage.getItem('webchat_name') || 'Visitante',
whatsapp: localStorage.getItem('webchat_whatsapp') || null,
message
})
});
if (res.ok) {
// Adicionar mensagem enviada
const chatMessages = document.getElementById('webchat-chat-messages');
const msgDiv = document.createElement('div');
msgDiv.style.cssText = 'background:#4F46E5;padding:10px 12px;border-radius:8px;max-width:80%;align-self:flex-end';
msgDiv.innerHTML = `<div style="color:white;font-size:14px">${message}</div>`;
chatMessages.appendChild(msgDiv);
chatMessages.scrollTop = chatMessages.scrollHeight;
input.value = '';
}
} catch (err) {
alert('Erro ao enviar mensagem');
}
};
// Enviar com Enter
document.getElementById('webchat-chat-input').onkeypress = (e) => {
if (e.key === 'Enter') {
document.getElementById('webchat-chat-send').click();
}
};
// Se já tem visitorId, restaurar chat (histórico + polling)
if (visitorId) {
const savedName = localStorage.getItem('webchat_name');
const savedWhatsapp = localStorage.getItem('webchat_whatsapp');
if (savedName && savedWhatsapp) {
if (document.getElementById('webchat-name')) {
document.getElementById('webchat-name').value = savedName;
}
if (document.getElementById('webchat-whatsapp')) {
document.getElementById('webchat-whatsapp').value = savedWhatsapp;
}
document.getElementById('webchat-form').style.display = 'none';
document.getElementById('webchat-chat').style.display = 'flex';
const chatMessages = document.getElementById('webchat-chat-messages');
if (chatMessages) chatMessages.innerHTML = '';
startPolling();
}
}
})();
</script>Antes do visitante preencher o formulário, exiba um aviso/termo informando que ao fornecer o número de WhatsApp ele autoriza a empresa a entrar em contato por este canal. Esse aviso já está incluído no exemplo do widget acima.
| Header | Valor |
|---|---|
x-api-key | Sua API Key obrigatório |
Content-Type | application/json |
| Campo | Tipo | Descrição |
|---|---|---|
visitorId | string | ID único do visitante (para continuar conversa) obrigatório |
visitorName | string | Nome do visitante |
whatsapp | string | Número de WhatsApp do visitante |
message | string | Conteúdo da mensagem obrigatório |
curl -X POST "https://sua-api.com.br/api/webhook/webchat/SEU_TOKEN" \
-H "Content-Type: application/json" \
-H "x-api-key: SUA_API_KEY" \
-d '{
"visitorId": "visitor_123456",
"visitorName": "João Silva",
"whatsapp": "5511999999999",
"message": "Olá, gostaria de saber mais sobre o produto"
}'{
"ok": true,
"chatId": 123,
"messageId": 456
}| Header | Valor |
|---|---|
x-api-key | Sua API Key obrigatório |
| Parâmetro | Tipo | Descrição |
|---|---|---|
lastMessageId | integer | ID da última mensagem recebida (opcional, para buscar apenas novas mensagens) |
curl -X GET "https://sua-api.com.br/api/webchat/messages/SEU_TOKEN/visitor_123456?lastMessageId=0" \
-H "x-api-key: SUA_API_KEY"{
"success": true,
"messages": [
{
"id": 123,
"text": "Olá! Como posso ajudar?",
"type": "text",
"mediaUrl": null,
"mediaType": null,
"timestamp": "2025-01-07T12:00:00.000Z"
}
]
}Use o visitorId para manter a conversa do mesmo
visitante. Armazene-o no localStorage do navegador.
Quando o sistema recebe uma mensagem do webchat via webhook, ele deve responder usando o endpoint padrão de envio de mensagens:
phoneNumber do chat será o visitorId (ex: visitor_1767028189276_48do2jntw)chatId retornado no webhook para identificar o chat corretoPOST /api/whatsapp/connections/123/messages
Authorization: Bearer SEU_TOKEN
Content-Type: application/json
{
"to": "visitor_1767028189276_48do2jntw",
"type": "text",
"text": "Olá! Recebi sua mensagem e já estou verificando..."
}Não use o número de WhatsApp real do visitante no campo to. Use sempre o visitorId que foi usado como phoneNumber no chat. Isso evita duplicação de chats.
Este endpoint público retorna as configurações do widget (título, cor, mensagem de boas-vindas). Não requer autenticação.