API

Integrar chatbot e agente de IA ao atendimento

Contrato para conectar seu robô ao atendimento por mensagens do Interaflow.

Atualizado em

Como funciona

O nó Controle Externo entrega os turnos da conversa ao seu agente por webhook. Seu sistema recebe a mensagem e o contexto, decide o que fazer e retorna ações. O Interaflow envia a resposta pelo canal, transfere para uma fila humana ou segue para o encerramento configurado.

Este guia cobre atendimento por mensagens, com WhatsApp como caso de uso. Conectar áudio em tempo real de um robô de voz requer um escopo próprio de telefonia.

Preparar a integração

  1. Disponibilize um endpoint HTTPS que receba POST e responda JSON.
  2. Configure no nó Controle Externo a URL, um segredo compartilhado, o tempo de resposta e a janela de histórico.
  3. Defina as saídas de transferência, encerramento e erro. Configure uma fila de contingência quando necessária.
  4. Conecte o fluxo à rota do canal e use Testar webhook para verificar o contrato.
  5. Teste também uma conversa real de homologação, incluindo transferência e falha.

Mantenha a chave de API e o segredo do webhook apenas nos servidores da integração. São credenciais diferentes: o segredo verifica as entregas ao agente; a chave autentica consultas e callbacks feitos ao Interaflow.

Requisição do Interaflow ao agente

HeaderConteúdo
Content-Typeapplication/json
X-Interaflow-DeliveryUUID da tentativa de entrega, útil para diagnóstico
X-Interaflow-TenantID da organização
X-Interaflow-Signaturesha256= seguido do HMAC-SHA256 hexadecimal do corpo cru; presente quando há segredo configurado

Exemplo ilustrativo de um turno, com identificadores fictícios:

{
  "event": "conversation.turn",
  "conversation_id": "11111111-1111-4111-8111-111111111111",
  "session_id": "22222222-2222-4222-8222-222222222222",
  "tenant_id": "33333333-3333-4333-8333-333333333333",
  "channel": { "type": "whatsapp", "instance_id": "44444444-4444-4444-8444-444444444444" },
  "contact": { "identifier": "5511999990000", "name": "Cliente de teste" },
  "message": { "text": "Quero falar com o financeiro", "type": "text" },
  "history": [],
  "session": { "turn_index": 1, "is_first": true }
}

Use conversation_id para manter o estado do seu agente. O histórico traz os últimos turnos conforme a configuração, com role, text e ts, do mais antigo para o mais recente. Com agrupamento de mensagens habilitado, uma sequência de mensagens pode chegar como um único turno.

Áudio recebido pode chegar com message.type: "audio" e a transcrição em message.text; trate também texto vazio quando não houver transcrição. O contrato não envia binários ou URLs de imagem, vídeo e documento.

Validar a assinatura

Configure um segredo e valide o HMAC sobre os bytes exatos recebidos, antes de processar o JSON. Não reconstrua o corpo com JSON.stringify para calcular a assinatura.

import { createHmac, timingSafeEqual } from "node:crypto";
 
export function assinaturaValida(rawBody, signature, secret) {
  if (!secret || typeof signature !== "string") return false;
  const expected = Buffer.from(
    "sha256=" + createHmac("sha256", secret).update(rawBody).digest("hex"),
    "utf8",
  );
  const received = Buffer.from(signature, "utf8");
  return received.length === expected.length
    && timingSafeEqual(received, expected);
}

Rejeite assinaturas ausentes ou inválidas. O identificador de entrega ajuda a reconhecer entregas já processadas. O contrato não inclui um header de timestamp assinado nem garante reenvio automático.

Responder e transferir para humano

Retorne HTTP 200 com um objeto actions contendo uma lista de ações:

{
  "actions": [
    { "type": "reply", "text": "Vou encaminhar você para o financeiro." },
    {
      "type": "handoff",
      "fila_id": "55555555-5555-4555-8555-555555555555",
      "note": "Cliente pede revisão da cobrança. Já informou o número do pedido."
    }
  ]
}

Substitua fila_id pelo UUID de uma fila válida da operação.

AçãoCampos e comportamento
replytext: envia a mensagem e mantém o agente no atendimento
handofffila_id opcional, note opcional: transfere à fila indicada ou segue a saída e o destino configurados no fluxo
endSegue a saída de encerramento do nó; sem saída conectada, encerra a sessão
waitPausa para resposta posterior via callback; hint_ms é uma indicação, não um agendamento

As ações são executadas em ordem. handoff, end e wait terminam o processamento desse turno: coloque as respostas reply antes delas. Uma lista vazia não envia resposta. A ação dial não origina chamadas neste contrato.

Resposta posterior por callback

Quando seu processamento exceder o tempo do turno síncrono, retorne wait:

{ "actions": [{ "type": "wait", "hint_ms": 12000 }] }

Ao terminar, envie as ações ao Interaflow. IF_BASE_URL é a origem HTTPS sem barra final, CONVERSATION_ID é o ID recebido no webhook e IF_API_KEY é uma chave da mesma organização:

curl -X POST "$IF_BASE_URL/api/v1/conversations/$CONVERSATION_ID/agent-callback" \
  -H "X-API-Key: $IF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotency_key": "consulta-pedido-001-resposta-1",
    "actions": [{ "type": "reply", "text": "A consulta foi concluída." }]
  }'

Use um idempotency_key próprio para cada resposta e preserve-o nas tentativas de envio da mesma resposta. O contrato recebe essa chave no corpo, não no header Idempotency-Key. O servidor reconhece a repetição da última chave processada na sessão; não use isso como garantia de deduplicação permanente de todas as respostas antigas.

O callback aceita X-API-Key ou Authorization: Bearer ik_... diretamente, sem exchange por JWT e sem vínculo obrigatório a usuário. O contrato atual verifica a organização da credencial; não aplica um escopo específico como conversations:write nesta rota.

HTTPSignificado
200Ações processadas; uma repetição reconhecida pode retornar duplicate: true
400Campo actions ausente ou não é uma lista
401Credencial inválida ou expirada
404Conversa não encontrada na organização da chave
409Conversa fora do Controle Externo, sessão encerrada ou atendimento já saiu do controle do robô
429Limite da chave excedido; respeite Retry-After

Ao receber 409, não insista em enviar mensagens por cima do atendimento humano. O estado da conversa pode ter mudado enquanto o agente processava a solicitação.

Diagnóstico e falhas

Consulte tentativas recentes com a mesma chave:

curl --get "$IF_BASE_URL/api/v1/agent-deliveries" \
  -H "X-API-Key: $IF_API_KEY" \
  --data-urlencode "conversation_id=$CONVERSATION_ID" \
  --data-urlencode "limit=50"

A resposta contém deliveries e count. Os filtros disponíveis são conversation_id, fluxo_id, since e limit (de 1 a 200). Essa consulta verifica a organização da credencial, sem escopo adicional por recurso no contrato atual. Os registros podem conter dados da conversa: restrinja o acesso à chave.

O teste pelo painel usa POST /api/v1/agent-deliveries/test, com autenticação de usuário JWT e corpo com fluxo_id e sample_text opcional. Ele confirma a comunicação com o webhook; não substitui o teste do canal e da fila humana.

Timeout, erro HTTP e resposta que não seja um objeto JSON contam como falhas. Não há retry automático da mesma entrega. Ao atingir o limite de falhas consecutivas, o fluxo tenta a saída de erro ou a fila configurada. Prepare essa contingência e teste a disponibilidade de atendimento. O padrão síncrono é 10 segundos, ajustável no nó, com teto de 30 segundos no transporte atual.

Evento de inatividade

Com uma régua de inatividade configurada, o mesmo webhook pode receber event: "conversation.idle". Não há uma nova message; o evento traz idle.seconds, idle.last_inbound_at, idle.last_speaker e idle.nudge_index, além do contexto da conversa. Seu agente responde com as mesmas ações.

Ative esse comportamento conforme as regras do canal e da operação. O evento só se aplica enquanto a conversa está sob Controle Externo.

Ver também