🌐 Integração Webchat

Adicione um chat ao vivo no seu site em poucos minutos

📋 Informações Necessárias

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

🚀 Passo a Passo

1

Criar uma conexão Webchat

Acesse o dashboard, vá em Conexões e crie uma nova conexão do tipo webchat. Anote o token e a webchatApiKey.

2

Adicionar o widget ao seu site

Copie e cole o código abaixo antes do fechamento da tag </body>:

Código do Widget

<!-- 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>

Consentimento (WhatsApp)

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.

🔌 API Reference

Enviar Mensagem

POST /api/webhook/webchat/:connectionToken

Headers

Header Valor
x-api-key Sua API Key obrigatório
Content-Type application/json

Body

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

Exemplo de Requisição

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"
  }'

Resposta de Sucesso

{
  "ok": true,
  "chatId": 123,
  "messageId": 456
}

Buscar Mensagens Recebidas (Polling)

GET /api/webchat/messages/:connectionToken/:visitorId

Headers

Header Valor
x-api-key Sua API Key obrigatório

Query Parameters

Parâmetro Tipo Descrição
lastMessageId integer ID da última mensagem recebida (opcional, para buscar apenas novas mensagens)

Exemplo de Requisição

curl -X GET "https://sua-api.com.br/api/webchat/messages/SEU_TOKEN/visitor_123456?lastMessageId=0" \
  -H "x-api-key: SUA_API_KEY"

Resposta de Sucesso

{
  "success": true,
  "messages": [
    {
      "id": 123,
      "text": "Olá! Como posso ajudar?",
      "type": "text",
      "mediaUrl": null,
      "mediaType": null,
      "timestamp": "2025-01-07T12:00:00.000Z"
    }
  ]
}
💡 Dica

Use o visitorId para manter a conversa do mesmo visitante. Armazene-o no localStorage do navegador.

📤 Como Enviar Respostas do Sistema

Quando o sistema recebe uma mensagem do webchat via webhook, ele deve responder usando o endpoint padrão de envio de mensagens:

POST /api/whatsapp/connections/:connectionId/messages

Importante

Exemplo de Resposta do Sistema

POST /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..."
}
⚠️ Atenção

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.

🎨 Configurações do Widget

GET /api/webchat/widget/:connectionToken

Este endpoint público retorna as configurações do widget (título, cor, mensagem de boas-vindas). Não requer autenticação.