Skip to main content

Eingehende Webhooks

Dynamisches Agenten-Routing — Finn ruft Ihren Server auf, wenn ein eingehender Anruf eintrifft.

6 min read

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

FeldErforderlich?Hinweise
finn_idJaWelcher Agent antwortet. Muss zu Ihrer Organisation gehören.
languageNeinÜberschreibt die Standardsprache des Agenten. en-US, hi-IN, es-ES usw.
variablesNeinFreies Key-Value-Objekt. Im Prompt verfügbar als {variable_name}.
knowledge_base_idsNeinÜberschreibt, welche Wissensdatenbanken für diesen Anruf geladen werden.
metadataNeinWird an den Anrufdatensatz und den Post-Call-Webhook angehängt. Für eigene Analyse-Tags nutzbar.
recording_enabledNeinÜberschreibt die Standardeinstellung des Agenten.
max_call_duration_secondsNeinHartes 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.

MetrikZielwert
Antwortzeit< 500 ms (p99)
Timeout1000 ms
Fallback bei TimeoutAuf der Telefonnummer konfigurierter Standard-Agent
Fallback bei 5xxStandard-Agent
Fallback bei ungültigem JSONStandard-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:

MusterAnwendungsfall
Nachschlagen + personalisierenKundendatensatz abrufen, Name + Stufe als Variablen übergeben
DNC-DurchsetzungAnrufe von gesperrten Nummern ablehnen
VIP-RoutingAgent überspringen, direkt an menschlichen Desk weiterleiten
Spracherkennunghi-IN für Indien wählen, en-US für Anrufer aus den USA
A/B-Tests50 % der Anrufe an eine neue Agentenversion leiten
Routing außerhalb der GeschäftszeitenAnderer Agent (oder Mailbox) außerhalb der Geschäftszeiten
Kampagnen-TrackingAnrufe von bestimmten Tracking-Nummern mit einer Kampagnen-ID versehen
Mandantenfähiges SaaSAn 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

SymptomLösung
Anrufe landen immer beim Standard-AgentenIhr Endpunkt braucht > 500 ms. Prüfen Sie die Zeitangaben im Webhook-Log von Finn.
Anrufer hört 2–3 s Stille, bevor der Agent sprichtIhr Endpunkt ist langsam, aber noch unter dem Timeout. Auf < 200 ms optimieren.
Variablen tauchen in der Agentenansprache nicht aufAbweichung zwischen Prompt-Platzhalter {customer_name} und Webhook-Schlüssel customerName. Auf beiden Seiten snake_case verwenden.
Falscher Agent hat geantwortetIhr Endpunkt hat eine finn_id zurückgegeben, die zu einer anderen Organisation gehört. Eigentümerschaft prüfen.
action: reject wird nicht berücksichtigtPrü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.