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
- Disponibilize um endpoint HTTPS que receba
POSTe responda JSON. - Configure no nó Controle Externo a URL, um segredo compartilhado, o tempo de resposta e a janela de histórico.
- Defina as saídas de transferência, encerramento e erro. Configure uma fila de contingência quando necessária.
- Conecte o fluxo à rota do canal e use Testar webhook para verificar o contrato.
- 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
| Header | Conteúdo |
|---|---|
Content-Type | application/json |
X-Interaflow-Delivery | UUID da tentativa de entrega, útil para diagnóstico |
X-Interaflow-Tenant | ID da organização |
X-Interaflow-Signature | sha256= 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ção | Campos e comportamento |
|---|---|
reply | text: envia a mensagem e mantém o agente no atendimento |
handoff | fila_id opcional, note opcional: transfere à fila indicada ou segue a saída e o destino configurados no fluxo |
end | Segue a saída de encerramento do nó; sem saída conectada, encerra a sessão |
wait | Pausa 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.
| HTTP | Significado |
|---|---|
200 | Ações processadas; uma repetição reconhecida pode retornar duplicate: true |
400 | Campo actions ausente ou não é uma lista |
401 | Credencial inválida ou expirada |
404 | Conversa não encontrada na organização da chave |
409 | Conversa fora do Controle Externo, sessão encerrada ou atendimento já saiu do controle do robô |
429 | Limite 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.