Skip to main content

Webhooks de Entrada

Roteamento dinâmico de agentes — o Finn chama o seu servidor quando uma chamada recebida chega.

6 min read

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

CampoObrigatório?Observações
finn_idSimQual agente atende. Deve pertencer à sua organização.
languageNãoSobrescreve o idioma padrão do agente. en-US, hi-IN, es-ES etc.
variablesNãoConjunto livre de chave/valor. Disponível no prompt como {variable_name}.
knowledge_base_idsNãoSobrescreve quais bases de conhecimento são carregadas nesta chamada.
metadataNãoAnexado ao registro da chamada e ao webhook pós-chamada. Use para sua própria marcação de analytics.
recording_enabledNãoSubstitui o padrão do agente.
max_call_duration_secondsNãoLimite 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étricaMeta
Tempo de resposta< 500 ms (p99)
Tempo limite1000 ms
Alternativa em caso de tempo limiteAgente padrão configurado no número de telefone
Alternativa em caso de erro 5xxAgente padrão
Alternativa em caso de JSON inválidoAgente 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ãoCaso de uso
Consulta + personalizaçãoBusca o registro do cliente e passa nome + nível como variáveis
Aplicação de DNCRejeita chamadas de números bloqueados
Roteamento VIPPula o agente e transfere direto para o atendimento humano
Detecção de idiomaEscolhe hi-IN para a Índia e en-US para quem liga dos EUA
Testes A/BRoteia 50% das chamadas para uma nova versão do agente
Roteamento fora do horárioAgente diferente (ou caixa postal) fora do horário comercial
Rastreamento de campanhaMarca chamadas de números de rastreamento específicos com um ID de campanha
SaaS multi-inquilinoRoteia 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

SintomaSolução
As chamadas sempre caem no agente padrãoSeu 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 falarSeu endpoint está lento, mas dentro do tempo limite. Otimize para menos de 200 ms.
Variáveis não aparecem na fala do agenteDivergência entre o placeholder do prompt {customer_name} e a chave do webhook customerName. Use snake_case nos dois lados.
O agente errado atendeuSeu endpoint retornou um finn_id que pertence a outra organização. Verifique a propriedade.
action: reject não respeitadoVerifique 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.