O widget do site coloca uma conversa com seu agente em qualquer página sua. Quem visita o site conversa com o mesmo agente que atende seus outros canais, e a conversa aparece em Conversas como as demais. Esta página mostra como instalar o script, como enviar dados da página para o agente e, para quem constrói a própria interface, como funciona a API pública por trás dele.
Instalar o script
Cada widget tem uma chave pública. Cole o script no HTML das páginas onde a conversa deve aparecer, trocando a chave pela do seu widget:
<script src="https://api.interage.ai/widget/v1.js" data-key="SUA_CHAVE_PUBLICA" async></script>
A chave pública não é um segredo: ela aparece no HTML do site. O que protege o widget é a lista de domínios permitidos. O widget só abre em sites dessa lista, e a lista vale também para cada chamada da conversa.
Enviar o contexto da página
Use window.Interage para dizer ao agente o que a pessoa está vendo, como o
imóvel aberto, o plano consultado ou a página atual. O agente lê esses dados
no próximo turno e responde com mais precisão.
Interage.setContext({ pagina: 'imovel-1234', plano: 'premium', logado: true })
Interage.open()
Interage.close()
Interage.isOpen() // true ou false
| Chamada | O que faz |
|---|---|
Interage.setContext(objeto) | Informa ou atualiza o contexto. O último valor de cada chave vale. |
Interage.open() | Abre a janela do widget. |
Interage.close() | Fecha a janela. |
Interage.isOpen() | Devolve true quando a janela está aberta. |
Interage.identify({ token }) | Identifica o usuário logado no seu site (veja abaixo). |
Interage.reset() | Chame no logout: descarta a conversa aberta nesta página. Quem voltar e for identificado de novo retoma a própria conversa. Com Exigir identificação ligado, o botão some até o próximo Interage.identify. |
Os métodos acima só existem depois que o script carrega. Para enviar o contexto ou abrir a janela antes disso, declare a fila antes do script e empilhe as chamadas nela:
<script>
window.Interage = window.Interage || { q: [] }
Interage.q.push(['setContext', { pagina: 'imovel-1234' }])
Interage.q.push(['open'])
</script>
<script src="https://api.interage.ai/widget/v1.js" data-key="SUA_CHAVE_PUBLICA" async></script>
Ao carregar, o widget executa a fila uma vez, na ordem, e troca
window.Interage pelos métodos de verdade. Daí em diante, chame os métodos
direto: o que for empilhado em Interage.q depois do carregamento é ignorado.
| Item da fila | Efeito |
|---|---|
['setContext', objeto] | Guarda o contexto. Várias chamadas se somam, e o último valor de cada chave vale. Ele segue junto quando a conversa abre |
['open'] | Abre a janela assim que o widget aparece na página |
['close'] | Mantém a janela fechada. Entre open e close, vale o último da fila |
['identify', { token }] | Guarda o token de identificação; ele segue junto quando a conversa abre |
isOpen não entra na fila. Ele devolve false até o widget aparecer na
página, e o widget não aparece quando está desligado, sem domínio ou num site
fora da lista.
Formato do contexto
O contexto é um objeto plano. O que não cabe nas regras abaixo é descartado em silêncio, sem erro.
| Regra | Valor |
|---|---|
| Chaves | No máximo 30 |
| Nome da chave | De 1 a 40 caracteres: letras, números, _, . e - |
| Valor | Texto, número ou verdadeiro/falso. Objetos e listas são descartados |
| Texto | Truncado em 500 caracteres. Quebras de linha e os símbolos < e > são neutralizados |
| Tamanho total | No máximo 4 KB depois de serializado |
Na conversa, o painel mostra a página atual e o contexto recebido. A página
atual é lida das chaves pagina, page ou url, nessa ordem.
Identificar o usuário logado
Em áreas logadas, seu servidor pode provar quem é a pessoa. Gere no servidor
um JWT HS256 assinado com o segredo idsec_… do widget e entregue-o à
página:
Interage.identify({ token: '<JWT gerado no seu servidor>' })
O token leva sub (o id do usuário no seu sistema, obrigatório), iat e
exp (no máximo 24 h entre eles) e, se quiser, name, email, phone e
context. Com o token válido, a conversa fica marcada como identidade
verificada e é ligada ao contato que já existe no CRM. O mesmo sub volta
sempre à mesma conversa, inclusive em outro navegador. Se a conversa aberta
for de outro usuário, o widget a descarta e abre a do usuário atual.
A conversa identificada não fica guardada no navegador: ao recarregar a
página, ela volta quando você chama Interage.identify de novo. Só a conversa
de visitante anônimo fica guardada, por até 30 dias.
Nunca coloque o segredo idsec_… na página: ele fica só no seu servidor.
Com Exigir identificação ligado, o botão do widget só aparece depois de
Interage.identify.
A API pública
O script usa a API pública abaixo. Você só precisa dela para montar uma
interface própria no lugar do widget pronto. Todas as rotas ficam em
https://api.interage.ai/api/public/v1/widget.
| Método | Rota | O que faz |
|---|---|---|
GET | /:publicKey/config | Configuração pública do widget: aparência, saudação, pré-chat, identityRequired e se está disponível |
POST | /:publicKey/sessions | Abre a conversa e devolve sessionId, token, status e resumed |
GET | /sessions/:id/messages | Lê a conversa. Sem after, devolve as mais recentes em ordem cronológica; com after (data ISO), só as posteriores a ela. limit vai até 200 |
POST | /sessions/:id/messages | Envia uma mensagem de texto, com anexos e contexto opcionais |
POST | /sessions/:id/attachments | Sobe um anexo antes de enviá-lo na mensagem |
PATCH | /sessions/:id/context | Atualiza o contexto sem enviar mensagem |
POST | /sessions/:id/read | Marca a conversa como lida pela pessoa |
POST | /sessions/:id/identify | Identifica a conversa já aberta com { identityToken } |
GET | /sessions/:id/events | Fluxo de eventos em tempo real: mensagem nova, "digitando" e mudança de estado |
Abrir a conversa
POST /:publicKey/sessions exige o cabeçalho Origin de um domínio
permitido e o token do desafio Turnstile (turnstileToken), que prova que
quem abre a conversa não é um robô. Opcionalmente, o corpo leva o pré-chat
(prechat com name, phone, email), o context e o identityToken
(o JWT de identificação).
A resposta traz o token da conversa. Guarde-o: ele só é devolvido uma vez.
Com identityToken de um usuário que já tem conversa neste widget, a resposta
volta com resumed: true e um token novo dessa conversa; o token anterior
deixa de valer.
POST /sessions/:id/identify identifica uma conversa aberta sem token. O
mesmo sub de novo responde 200. Outro sub, ou um sub que já tem outra
conversa neste widget, responde 409 identity_mismatch: abra uma conversa
nova com o token.
Obter o turnstileToken
O desafio só vale nos domínios cadastrados por nós, então ele roda numa página da API aberta num iframe no seu site:
- Crie um iframe com
https://api.interage.ai/widget/v1/turnstile?origin=<location.origin>&key=<chave pública>. A página só abre seoriginestiver nos domínios permitidos do widget e só pode ser emoldurada por essa origem; fora disso, responde403. - Escute
messagena janela do seu site. Aceite só eventos comevent.originigual à origem da API (https://api.interage.ai), vindos do próprio iframe (event.source === iframe.contentWindow) e comtype: 'interage-widget-turnstile'. - A página manda
{ type: 'interage-widget-turnstile', token }quando o desafio passa, ou{ type: 'interage-widget-turnstile', error: true }quando falha, expira ou não carrega. Remova o iframe depois da resposta. - Envie o
tokenemturnstileToken. Ele vale para uma abertura só: em caso de erro, abra um iframe novo.
O desafio roda no modo interaction-only: em geral passa sem mostrar nada,
então o iframe pode começar invisível. Quando o Cloudflare pede uma interação,
o desafio aparece dentro do iframe. Por isso, se a resposta demorar alguns
segundos, deixe o iframe visível para a pessoa resolver o desafio. O widget
pronto mostra o iframe depois de 3 segundos e desiste em 20.
Token da conversa
Depois de aberta, toda chamada leva o token no cabeçalho x-widget-token.
Nunca o envie na URL. A empresa e o widget saem da própria sessão, não do
corpo do pedido. A conversa vale por 30 dias desde a última atividade; depois
disso o token deixa de valer e é preciso abrir outra conversa.
Enviar mensagem
POST /sessions/:id/messages recebe:
| Campo | Obrigatório | Descrição |
|---|---|---|
clientMessageId | Sim | Identificador que você gera para a mensagem. Repetir o mesmo valor não duplica: a resposta volta com duplicate: true |
text | Não | Texto da mensagem |
attachments | Não | Lista de { objectKey } devolvidos pela rota de anexos, no máximo 10 por mensagem |
context | Não | Contexto do site, no formato acima |
A resposta é { messageId, duplicate, capped }. A resposta do agente não vem
nela: busque em GET /sessions/:id/messages?after=, passando em after a
data ISO (at) da última mensagem que você já tem, ou use o fluxo de eventos. Os eventos têm os tipos message_created, typing_started,
typing_heartbeat, typing_stopped e state_changed.
Códigos de erro
Os erros voltam como { "error": "<código>", "message": "<texto>" }.
| Código | HTTP | Quando acontece |
|---|---|---|
invalid_input | 400 | Dado inválido: telefone, e-mail, contexto fora do formato, anexo recusado, corpo fora do formato da rota ou ilegível |
invalid_token | 401 | Token ausente, errado ou de outra conversa |
invalid_identity | 401 | Token de identificação inválido, vencido ou assinado com outro segredo |
session_expired | 401 | A conversa passou de 30 dias sem atividade |
origin_denied | 403 | O site que chamou não está nos domínios permitidos |
unavailable | 403 | O widget está desligado ou sem domínios |
turnstile_failed | 403 | O desafio anti-robô não foi confirmado |
identity_required | 403 | O widget exige identificação e a abertura veio sem identityToken válido |
identity_mismatch | 409 | A conversa já é de outro usuário, ou o usuário já tem outra conversa |
not_found | 404 | A chave pública não existe |
rate_limited | 429 | Passou do limite por endereço ou por minuto (veja abaixo) ou do limite geral de requisições da API. Neste último caso, o corpo traz também retryAfter, em segundos, repetido no cabeçalho Retry-After |
forward_failed | 503 | A mensagem não pôde ser entregue agora. Tente de novo com o mesmo clientMessageId |
Limites e o que acontece em cada teto
Cada mensagem respondida pela IA é cobrada da sua empresa. Os limites impedem que alguém use seu widget para gerar custo. Você ajusta os quatro valores nas configurações do widget, dentro das faixas abaixo.
| Limite | Padrão | Faixa | Ao atingir |
|---|---|---|---|
| Conversas por endereço por hora | 5 | 1 a 50 | 429 rate_limited ao abrir outra conversa |
| Mensagens por minuto | 10 | 2 a 60 | 429 rate_limited no envio; a pessoa pode tentar de novo em seguida |
| Mensagens por conversa | 200 | 20 a 2.000 | A conversa passa para a equipe e a IA deixa de responder. O envio devolve capped: true e o estado fica capped |
| Conversas por dia | 500 | 10 a 20.000 | Novos visitantes recebem status: "lead": veem um formulário para deixar contato e a IA não responde. Quem já está conversando continua |
Um valor fora da faixa é recusado com 400.