Webhooks de Entrada
Roteamento dinâmico de agentes — o Finn chama o seu servidor quando uma chamada recebida chega.
Webhooks de entrada
Quando uma chamada de entrada chega, o Finn pode perguntar ao seu servidor, em tempo real, com qual agente atender, quais variáveis injetar e qual base de conhecimento carregar. Isso permite roteamento dinâmico — por número do chamador, nível da conta, horário do dia, coorte de teste A/B ou qualquer lógica que seu backend utilize.
Se um agente fixo for suficiente, ignore esta página. Se quiser roteamento dinâmico por chamada, é aqui.
Como funciona
caller dials → Finn answers ring → Finn POSTs to your URL → your server returns agent + vars → Finn streams the voice agent
O handshake adiciona cerca de 100–200 ms de latência. Seu endpoint precisa responder em menos de 500 ms, ou o Finn recorre ao agente padrão.
Configurar
1. Defina a URL do webhook de entrada
Painel → Configurações → Números de telefone → [número] → URL do webhook de entrada.
Cole seu endpoint HTTPS e salve. O Finn faz um ping único com um corpo {"ping": true} para verificar se está acessível.
Via API
curl https://api.hirefinn.ai/v1/phone-numbers/ph_1234 \
-X PATCH \
-H "Authorization: Bearer $FINN_API_KEY" \
-d '{ "inbound_webhook_url": "https://your-app.com/finn/inbound" }'
2. Defina um agente de fallback
Configure um Finn padrão para esse número — usado se o webhook expirar, falhar ou retornar uma resposta inválida.
Payload da requisição
O Finn envia um POST para sua URL com:
{
"session_id": "ws_2H4abc",
"request_type": "inbound",
"phone_number_id": "ph_1234",
"channel": "pstn",
"from": {
"phone": "+919876543210",
"country": "IN",
"carrier": "Airtel"
},
"to": {
"phone": "+918765432100",
"country": "IN"
},
"received_at": "2026-05-22T14:30:00Z",
"metadata": {}
}
Para chamadas do WhatsApp, o bloco from usa campos específicos do WhatsApp:
"from": {
"wa_id": "919876543210",
"display_name": "Priya M",
"profile_pic_url": "https://..."
},
"channel": "whatsapp"
Resposta
Retorne um corpo JSON em até 500 ms descrevendo como rotear a chamada:
{
"finn_id": "fn_def456",
"language": "hi-IN",
"variables": {
"customer_name": "Priya M",
"account_tier": "premium",
"last_order_id": "ord_99831",
"preferred_agent": "Aria"
},
"knowledge_base_ids": ["kb_general", "kb_premium_perks"],
"metadata": {
"campaign_tag": "premium-support-q2",
"ab_cohort": "B"
},
"recording_enabled": true,
"max_call_duration_seconds": 600
}
Referência de campos
| Campo | Obrigatório? | Observações |
|---|---|---|
finn_id | Sim | Qual agente atende. Deve pertencer à sua organização. |
language | Não | Sobrescreve o idioma padrão do agente. en-US, hi-IN, es-ES etc. |
variables | Não | Conjunto livre de chave/valor. Disponível no prompt como {variable_name}. |
knowledge_base_ids | Não | Sobrescreve quais bases de conhecimento são carregadas nesta chamada. |
metadata | Não | Anexado ao registro da chamada e ao webhook pós-chamada. Use para sua própria marcação de analytics. |
recording_enabled | Não | Substitui o padrão do agente. |
max_call_duration_seconds | Não | Limite máximo. O padrão é 1800 (30 min). |
Rejeitar a chamada
{ "action": "reject", "reason": "blocked_caller" }
Finn encerra a chamada com uma mensagem de saída configurada ("Este número não está mais em serviço"). Use para aplicar DNC, contas bloqueadas ou desligamentos fora do horário de atendimento.
Transferir imediatamente
{ "action": "transfer", "to": "+918888888888", "reason": "vip_route" }
Ignora completamente o agente de IA — encaminha direto para um humano. Útil para níveis VIP / de escalonamento.
Exemplo de implementação (Node)
import express from "express";
const app = express();
app.use(express.json());
app.post("/finn/inbound", async (req, res) => {
const { from, to, channel } = req.body;
// 1. Look up caller in CRM (must be fast — DB index by phone)
const phone = from.phone ?? `+${from.wa_id}`;
const customer = await crm.findByPhone(phone);
// 2. Block known DNC
if (customer?.dnc) {
return res.json({ action: "reject", reason: "dnc" });
}
// 3. VIP → straight to human
if (customer?.tier === "vip") {
return res.json({
action: "transfer",
to: process.env.VIP_DESK_NUMBER!,
reason: "vip_route",
});
}
// 4. Localized agent based on caller country
const language = from.country === "IN" ? "hi-IN" : "en-US";
// 5. Pick agent + load context
return res.json({
finn_id: customer?.tier === "premium"
? "fn_premium_aria"
: "fn_standard_aria",
language,
variables: {
customer_name: customer?.name ?? "there",
account_tier: customer?.tier ?? "standard",
last_order_id: customer?.last_order_id ?? "",
},
knowledge_base_ids:
customer?.tier === "premium" ? ["kb_general", "kb_premium"] : ["kb_general"],
metadata: { ab_cohort: customer?.ab_cohort ?? "A" },
});
});
app.listen(3000);
Verificação de assinatura
Mesmo esquema dos webhooks pós-chamada — HMAC-SHA256 sobre o corpo bruto, cabeçalho X-Finn-Signature.
const sig = req.headers["x-finn-signature"] as string;
const ok = verifyFinnSignature(rawBody, sig, process.env.FINN_INBOUND_SECRET!);
if (!ok) return res.status(401).send("bad signature");
Consulte Webhooks pós-chamada para a implementação completa da verificação.
Requisitos de desempenho
Isto está no caminho crítico — quem ligou está ouvindo o toque enquanto aguarda sua resposta.
| Métrica | Meta |
|---|---|
| Tempo de resposta | < 500 ms (p99) |
| Tempo limite | 1000 ms |
| Alternativa em caso de tempo limite | Agente padrão configurado no número de telefone |
| Alternativa em caso de erro 5xx | Agente padrão |
| Alternativa em caso de JSON inválido | Agente padrão + erro registrado |
Dicas para ficar abaixo de 500 ms
- Armazene em cache as consultas ao CRM por número de telefone durante 5 minutos
- Use um banco de dados colocalizado — webhook em us-east e banco em us-west = 80 ms em cada sentido
- Pré-calcule as decisões de roteamento — guarde a resposta no registro do cliente, não decida em tempo real
- Pule enriquecimentos não essenciais no salto de entrada — deixe esse trabalho para o webhook pós-chamada
Pré-triagem de quem liga
A maioria das aplicações usa o webhook de entrada para um destes padrões:
| Padrão | Caso de uso |
|---|---|
| Consulta + personalização | Busca o registro do cliente e passa nome + nível como variáveis |
| Aplicação de DNC | Rejeita chamadas de números bloqueados |
| Roteamento VIP | Pula o agente e transfere direto para o atendimento humano |
| Detecção de idioma | Escolhe hi-IN para a Índia e en-US para quem liga dos EUA |
| Testes A/B | Roteia 50% das chamadas para uma nova versão do agente |
| Roteamento fora do horário | Agente diferente (ou caixa postal) fora do horário comercial |
| Rastreamento de campanha | Marca chamadas de números de rastreamento específicos com um ID de campanha |
| SaaS multi-inquilino | Roteia para o inquilino cujo número foi discado |
Testes
Use a CLI do Finn para simular chamadas de entrada sem um toque real na PSTN:
finn inbound simulate \
--phone-number-id ph_1234 \
--from +919876543210 \
--webhook-url https://your-app.com/finn/inbound
A saída mostra a resposta do seu endpoint, a latência e o agente + variáveis resolvidos. Compatível com CI.
Problemas comuns
| Sintoma | Solução |
|---|---|
| As chamadas sempre caem no agente padrão | Seu endpoint leva mais de 500 ms. Verifique o tempo no log de webhook do Finn. |
| Quem liga ouve 2-3 s de silêncio antes de o agente falar | Seu endpoint está lento, mas dentro do tempo limite. Otimize para menos de 200 ms. |
| Variáveis não aparecem na fala do agente | Divergência entre o placeholder do prompt {customer_name} e a chave do webhook customerName. Use snake_case nos dois lados. |
| O agente errado atendeu | Seu endpoint retornou um finn_id que pertence a outra organização. Verifique a propriedade. |
action: reject não respeitado | Verifique se reason é uma string e se o JSON da resposta é válido. Respostas inválidas → fallback. |
Relacionados
Was this page helpful?
Still stuck or have feedback?
Email [email protected] or use the chat bubble in the bottom-right corner — it's a Finn that knows the Academy cold.