Webhooks entrants
Routage dynamique des agents — Finn appelle votre serveur lorsqu'un appel entrant arrive.
Webhooks entrants
Lorsqu'un appel entrant arrive, Finn peut demander en temps réel à votre serveur quel agent doit répondre, quelles variables injecter et quelle base de connaissances charger. Vous pouvez ainsi router dynamiquement : selon le numéro de l'appelant, le niveau de compte, l'heure de la journée, la cohorte A/B ou toute logique gérée par votre backend.
Si un agent fixe suffit, passez cette page. Si vous souhaitez un routage dynamique par appel, c'est ici.
Fonctionnement
caller dials → Finn answers ring → Finn POSTs to your URL → your server returns agent + vars → Finn streams the voice agent
Le handshake ajoute environ 100 à 200 ms de latence. Votre endpoint doit répondre en moins de 500 ms, sans quoi Finn bascule sur l'agent par défaut.
Configurer
1. Définir l'URL du webhook entrant
Tableau de bord → Paramètres → Numéros de téléphone → [numéro] → URL du webhook entrant.
Collez votre endpoint HTTPS. Enregistrez. Finn l'appelle une fois avec un corps {"ping": true} pour vérifier qu'il est joignable.
Via l'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. Définir un agent de repli
Configurez un Finn par défaut pour ce numéro — utilisé si votre webhook dépasse le délai, renvoie une erreur ou une réponse invalide.
Charge utile de la requête
Finn envoie une requête POST à votre URL avec :
{
"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": {}
}
Pour les appels WhatsApp, le bloc from utilise des champs spécifiques à WhatsApp :
"from": {
"wa_id": "919876543210",
"display_name": "Priya M",
"profile_pic_url": "https://..."
},
"channel": "whatsapp"
Réponse
Renvoyez un corps JSON en moins de 500 ms décrivant comment router l'appel :
{
"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
}
Référence des champs
| Champ | Requis ? | Remarques |
|---|---|---|
finn_id | Oui | Quel agent répond. Doit appartenir à votre organisation. |
language | Non | Remplace la langue par défaut de l'agent. en-US, hi-IN, es-ES, etc. |
variables | Non | Ensemble libre de paires clé/valeur. Accessible dans le prompt via {variable_name}. |
knowledge_base_ids | Non | Remplace les bases de connaissances chargées pour cet appel. |
metadata | Non | Joint à l'enregistrement de l'appel et au webhook post-appel. À utiliser pour votre propre étiquetage analytique. |
recording_enabled | Non | Remplace la valeur par défaut de l'agent. |
max_call_duration_seconds | Non | Limite stricte. Valeur par défaut : 1800 (30 min). |
Rejeter l'appel
{ "action": "reject", "reason": "blocked_caller" }
Finn met fin à l'appel avec un message sortant configuré (« Ce numéro n'est plus en service »). À utiliser pour l'application des listes DNC, les comptes bloqués ou les raccrochages en dehors des heures d'ouverture.
Transférer immédiatement
{ "action": "transfer", "to": "+918888888888", "reason": "vip_route" }
Contourne entièrement l'agent IA — acheminement direct vers un humain. Utile pour les niveaux VIP / escalade.
Exemple d'implémentation (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);
Vérification de la signature
Même schéma que les webhooks post-appel — HMAC-SHA256 sur le corps brut, en-tête 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");
Voir Webhooks post-appel pour l'implémentation complète de la vérification.
Exigences de performance
Ceci se situe sur le chemin critique — l'appelant entend la tonalité pendant qu'il attend votre réponse.
| Métrique | Cible |
|---|---|
| Temps de réponse | < 500 ms (p99) |
| Délai d'expiration | 1000 ms |
| Repli en cas d'expiration | Agent par défaut configuré sur le numéro de téléphone |
| Repli en cas d'erreur 5xx | Agent par défaut |
| Repli en cas de JSON invalide | Agent par défaut + erreur journalisée |
Conseils pour rester sous 500 ms
- Mettez en cache les recherches CRM par numéro de téléphone pendant 5 minutes
- Utilisez une base de données colocalisée — webhook depuis us-east, base de données dans us-west = 80 ms dans chaque sens
- Pré-calculez les décisions d'acheminement — enregistrez la réponse sur la fiche client, ne décidez pas en direct
- Ignorez l'enrichissement non essentiel lors du saut entrant — reportez ce travail sur le webhook post-appel
Présélection des appelants
La plupart des applications utilisent le webhook entrant pour l'un de ces modèles :
| Modèle | Cas d'usage |
|---|---|
| Recherche + personnalisation | Récupérer la fiche client, transmettre le nom et le niveau comme variables |
| Application de la liste rouge | Rejeter les appels provenant de numéros bloqués |
| Routage VIP | Ignorer l'agent, transférer directement vers un conseiller humain |
| Détection de la langue | Choisir hi-IN pour l'Inde, en-US pour les appelants américains |
| Tests A/B | Router 50 % des appels vers une nouvelle version de l'agent |
| Routage hors horaires | Agent différent (ou messagerie vocale) en dehors des heures d'ouverture |
| Suivi de campagne | Associer un ID de campagne aux appels provenant de numéros de suivi spécifiques |
| SaaS multi-locataire | Router vers le locataire dont le numéro a été composé |
Tests
Utilisez le CLI Finn pour simuler des appels entrants sans sonnerie PSTN réelle :
finn inbound simulate \
--phone-number-id ph_1234 \
--from +919876543210 \
--webhook-url https://your-app.com/finn/inbound
La sortie affiche la réponse de votre endpoint, la latence, ainsi que l'agent et les variables résolus. Compatible CI.
Pièges courants
| Symptôme | Correctif |
|---|---|
| Les appels basculent toujours vers l'agent par défaut | Votre endpoint dépasse 500 ms. Vérifiez les temps de réponse dans le journal des webhooks de Finn. |
| L'appelant entend 2 à 3 s de silence avant que l'agent ne parle | Votre endpoint est lent mais reste sous le délai d'expiration. Optimisez-le à moins de 200 ms. |
| Les variables n'apparaissent pas dans les propos de l'agent | Décalage entre l'espace réservé {customer_name} du prompt et la clé customerName du webhook. Utilisez le snake_case des deux côtés. |
| Le mauvais agent a répondu | Votre endpoint a renvoyé un finn_id appartenant à une autre organisation. Vérifiez la propriété. |
action: reject non pris en compte | Vérifiez que reason est une chaîne et que le JSON de réponse est valide. Réponses invalides → repli. |
Ressources associées
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.