Eingehende Webhooks
Dynamisches Agenten-Routing — Finn ruft Ihren Server auf, wenn ein eingehender Anruf eintrifft.
Eingehende Webhooks
Wenn ein eingehender Anruf eintrifft, kann Finn Ihren Server in Echtzeit fragen, welcher Agent antworten soll, welche Variablen eingefügt und welche Wissensdatenbank geladen werden soll. So lässt sich dynamisch routen – nach Anrufernummer, Kundenstufe, Tageszeit, A/B-Kohorte oder jeder anderen Logik Ihres Backends.
Wenn ein fester Agent ausreicht, überspringen Sie dieses Kapitel. Wenn Sie dynamisches Routing pro Anruf wollen, ist dies die richtige Seite.
Funktionsweise
caller dials → Finn answers ring → Finn POSTs to your URL → your server returns agent + vars → Finn streams the voice agent
Der Handshake verursacht ca. 100–200 ms zusätzliche Latenz. Ihr Endpunkt muss in unter 500 ms antworten, sonst greift Finn auf den Standard-Agenten zurück.
Einrichten
1. Webhook-URL für eingehende Anrufe festlegen
Dashboard → Einstellungen → Telefonnummern → [Nummer] → Inbound Webhook URL.
Fügen Sie Ihren HTTPS-Endpunkt ein und speichern Sie. Finn sendet einmalig einen Ping mit einem {"ping": true}-Body, um die Erreichbarkeit zu prüfen.
Über die 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. Fallback-Agenten festlegen
Konfigurieren Sie einen Standard-Finn für diese Nummer – er wird verwendet, wenn Ihr Webhook das Zeitlimit überschreitet, einen Fehler liefert oder eine ungültige Antwort zurückgibt.
Anfrage-Payload
Finn sendet einen POST an Ihre URL mit:
{
"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": {}
}
Bei WhatsApp-Anrufen enthält der from-Block WhatsApp-spezifische Felder:
"from": {
"wa_id": "919876543210",
"display_name": "Priya M",
"profile_pic_url": "https://..."
},
"channel": "whatsapp"
Antwort
Geben Sie innerhalb von 500 ms einen JSON-Body zurück, der das Routing des Anrufs beschreibt:
{
"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
}
Feldreferenz
| Feld | Erforderlich? | Hinweise |
|---|---|---|
finn_id | Ja | Welcher Agent antwortet. Muss zu Ihrer Organisation gehören. |
language | Nein | Überschreibt die Standardsprache des Agenten. en-US, hi-IN, es-ES usw. |
variables | Nein | Freies Key-Value-Objekt. Im Prompt verfügbar als {variable_name}. |
knowledge_base_ids | Nein | Überschreibt, welche Wissensdatenbanken für diesen Anruf geladen werden. |
metadata | Nein | Wird an den Anrufdatensatz und den Post-Call-Webhook angehängt. Für eigene Analyse-Tags nutzbar. |
recording_enabled | Nein | Überschreibt die Standardeinstellung des Agenten. |
max_call_duration_seconds | Nein | Hartes Limit. Standard ist 1800 (30 Min.). |
Anruf ablehnen
{ "action": "reject", "reason": "blocked_caller" }
Finn beendet den Anruf mit einer konfigurierten Ansage („Diese Nummer ist nicht mehr vergeben"). Geeignet für DNC-Durchsetzung, gesperrte Konten oder Auflegen außerhalb der Geschäftszeiten.
Sofort weiterleiten
{ "action": "transfer", "to": "+918888888888", "reason": "vip_route" }
Den KI-Agenten vollständig überspringen und direkt an eine Person weiterleiten. Nützlich für VIP- und Eskalationsstufen.
Implementierungsbeispiel (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);
Signaturprüfung
Gleiches Verfahren wie bei Post-Call-Webhooks — HMAC-SHA256 über den Rohtext des Bodys, Header 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");
Die vollständige Implementierung der Prüfung findest du unter Post-Call-Webhooks.
Leistungsanforderungen
Das liegt auf dem kritischen Pfad — der Anrufer hört das Freizeichen, während auf deine Antwort gewartet wird.
| Metrik | Zielwert |
|---|---|
| Antwortzeit | < 500 ms (p99) |
| Timeout | 1000 ms |
| Fallback bei Timeout | Auf der Telefonnummer konfigurierter Standard-Agent |
| Fallback bei 5xx | Standard-Agent |
| Fallback bei ungültigem JSON | Standard-Agent + Fehler protokolliert |
Tipps für < 500 ms
- CRM-Abfragen zwischenspeichern — pro Telefonnummer für 5 Minuten
- Datenbank am gleichen Standort betreiben — Webhook aus us-east, DB in us-west = 80 ms pro Richtung
- Routing-Entscheidungen vorberechnen — Ergebnis im Kundendatensatz ablegen, nicht live entscheiden
- Nicht zwingend nötige Anreicherung auslassen — diese Arbeit in den Post-Call-Webhook verlagern
Vorabprüfung des Anrufers
Die meisten Anwendungen nutzen den Inbound-Webhook für eines dieser Muster:
| Muster | Anwendungsfall |
|---|---|
| Nachschlagen + personalisieren | Kundendatensatz abrufen, Name + Stufe als Variablen übergeben |
| DNC-Durchsetzung | Anrufe von gesperrten Nummern ablehnen |
| VIP-Routing | Agent überspringen, direkt an menschlichen Desk weiterleiten |
| Spracherkennung | hi-IN für Indien wählen, en-US für Anrufer aus den USA |
| A/B-Tests | 50 % der Anrufe an eine neue Agentenversion leiten |
| Routing außerhalb der Geschäftszeiten | Anderer Agent (oder Mailbox) außerhalb der Geschäftszeiten |
| Kampagnen-Tracking | Anrufe von bestimmten Tracking-Nummern mit einer Kampagnen-ID versehen |
| Mandantenfähiges SaaS | An den Mandanten leiten, dessen Nummer gewählt wurde |
Testen
Mit der Finn CLI eingehende Anrufe simulieren, ohne echtes PSTN-Klingeln:
finn inbound simulate \
--phone-number-id ph_1234 \
--from +919876543210 \
--webhook-url https://your-app.com/finn/inbound
Die Ausgabe zeigt Endpunkt-Antwort, Latenz sowie den aufgelösten Agenten und die Variablen. CI-tauglich.
Häufige Stolperfallen
| Symptom | Lösung |
|---|---|
| Anrufe landen immer beim Standard-Agenten | Ihr Endpunkt braucht > 500 ms. Prüfen Sie die Zeitangaben im Webhook-Log von Finn. |
| Anrufer hört 2–3 s Stille, bevor der Agent spricht | Ihr Endpunkt ist langsam, aber noch unter dem Timeout. Auf < 200 ms optimieren. |
| Variablen tauchen in der Agentenansprache nicht auf | Abweichung zwischen Prompt-Platzhalter {customer_name} und Webhook-Schlüssel customerName. Auf beiden Seiten snake_case verwenden. |
| Falscher Agent hat geantwortet | Ihr Endpunkt hat eine finn_id zurückgegeben, die zu einer anderen Organisation gehört. Eigentümerschaft prüfen. |
action: reject wird nicht berücksichtigt | Prüfen, ob reason ein String und das Antwort-JSON gültig ist. Ungültige Antworten → Fallback. |
Verwandte Themen
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.