Dinamična konfiguracija za posamezen klic
Vsaki telefonski številki in objavljivemu ključu je privzeto dodeljen statični agent. Ko potrebujete prilagajanje za posameznega klicatelja ali za posameznega obiskovalca — usmerjanje VIP, kontekst prijavljenega uporabnika, A/B-preizkuse pozivov — preklopite v način webhook in naj odloči vaš strežnik.
Kako deluje
- Naročite se na dogodek
telephony.incoming(telefon) aliweb.incoming(gradnik). Oba sta blokirajoča webhooka: ThunderPhone pred nadaljevanjem klica na vaš odgovor čaka do 10 sekund. - ThunderPhone vam pošlje
{call_id, from_number, to_number}(seje gradnika namesto številk vsebujejo polja, značilna za gradnik — glejte shemo zahteve). - Vaš strežnik odgovori s konfiguracijo agenta (poziv, glas, izdelek, orodja). ThunderPhone to konfiguracijo uporabi za klic.
- Če vrnete
{}, pride do časovne omejitve ali napake, se kot nadomestna možnost uporabi statično dodeljeni agent. Varen privzeti način.
1. Konfigurirajte cilj webhooka
Telefonski klici
Za telefonske številke naročite svojo končno točko na telephony.incoming:
curl -X POST https://api.thunderphone.com/v1/developer/webhook-endpoints \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "Prod call-incoming",
"url": "https://example.com/thunderphone/incoming",
"events": ["telephony.incoming"]
}'
Odgovor vključuje enkratno vrednost secret — shranite jo; uporabili jo boste
za preverjanje podpisa.
Spletni gradnik
Za seje gradnika ustvarite objavljivi ključ v mode="webhook"
z vgrajenim URL-jem svoje končne točke:
curl -X POST https://api.thunderphone.com/v1/publishable-key \
-H "Authorization: Bearer sk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Dynamic widget",
"mode": "webhook",
"webhook_url": "https://example.com/thunderphone/widget-incoming",
"allowed_domains": ["example.com"]
}'
Gradnik bo ob vsakem začetku seje poslal zahtevo POST na ta URL.
2. Implementirajte obravnavalnik
Tri osnovna pravila:
- Preverite podpis pri vsaki zahtevi (glejte Preverjanje podpisov webhookov). Tega ne preskočite v razvoju — pravilno nastavite enkrat in znova uporabite.
- Odgovorite hitro. Deset sekund je stroga omejitev, vsaka sekunda pa je tišina za klicatelja. Po potrebi izvedite poizvedbe v zbirki podatkov, vendar ne kličite nadaljnjih LLM-jev sinhrono — če želite dinamično ustvarjanje pozivov, jih vnaprej izračunajte in shranite v predpomnilnik.
- Ustrezno uporabite nadomestno rešitev. Vsako nepričakovano stanje mora vrniti
{}, da statično dodeljeni agent obravnava klic.
import hashlib
import hmac
import json
import os
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]
def verify(body: bytes, sig: str) -> bool:
expected = hmac.new(SECRET.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, sig or "")
@app.post("/thunderphone/incoming")
async def incoming(request: Request):
body = await request.body()
if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
raise HTTPException(401)
event = json.loads(body)
if event["type"] not in ("telephony.incoming", "web.incoming"):
return {} # fall back to default
caller = event["data"]["from_number"]
# Cheap DB lookup: is this a known VIP?
customer = lookup_customer(caller)
if customer and customer.tier == "vip":
return {
"prompt": f"You are a VIP concierge for {customer.name}. Be proactive…",
"voice": "john",
"product": "storm-base",
}
return {} # default agent handles non-VIPs
def lookup_customer(phone: str):
# ... your CRM integration ...
pass
import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;
function verify(body, sig) {
const expected = crypto.createHmac("sha256", SECRET).update(body).digest("hex");
return sig &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(sig));
}
app.post(
"/thunderphone/incoming",
express.raw({ type: "application/json" }),
async (req, res) => {
if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
const IMPORTANT_TYPES = new Set([
"telephony.incoming",
"web.incoming",
]);
if (!IMPORTANT_TYPES.has(event.type)) return res.json({});
const customer = await lookupCustomer(event.data.from_number);
if (customer?.tier === "vip") {
return res.json({
prompt: `You are a VIP concierge for ${customer.name}. Be proactive…`,
voice: "john",
product: "storm-base",
});
}
res.json({}); // fall back to default agent
},
);
3. Shema odgovora
Telo odgovora se natančno ujema s odzivno shemo za dohodni klic. Pogosto uporabljena polja:
| Polje | Vrsta | Opis |
|---|---|---|
prompt | niz (obvezno) | Sistemski poziv za agenta |
voice | niz (obvezno) | ID glasu iz GET /v1/voices |
product | niz | Privzeto je spark |
background_track | niz | null | ID ambientalnega zvoka |
acknowledgement_prompt_mode | niz | auto ali manual (samo Storm s potrditvijo) |
acknowledgement_prompt | niz | Obvezno, kadar je način manual |
tools | polje | Vdelane sheme funkcijskih orodij — glejte Funkcijska orodja |
Vzorci
Kontekst prijavljenega uporabnika
V gradnikih v načinu webhook stran obiskovalca že ve, kdo je.
Pokličite svoj webhook s parametrom poizvedbenega niza, ki ga SDK gradnika
posreduje naprej (?customer_id=123), in poiščite stranko na strani strežnika.
Uvajanje pozivov A/B
Preden to izdelate sami, upoštevajte, da ima ThunderPhone vgrajeno funkcijo
Eksperimenti
(/dashboard/experiments in zavihek A/B gradnika agenta), ki
določa različice, razdeli promet in primerja rezultate za posamezno različico —
webhook ni potreben.
Če vseeno potrebujete nadzor na strani webhooka: zgostite call_id → vedro;
za 0..49 uporabite poziv A, za 50..99 pa poziv B. Zabeležite, katero
vedro ste izbrali, v svoji podatkovni zbirki in ga pozneje povežite z oceno
zaključenega klica.
Usmerjanje glede na čas
Delovni čas → agent za »podporo v živo«; izven delovnega časa → agent za »sprejem sporočil«.
Čisto preklapljanje na podlagi new Date().getUTCHours() v vašem obdelovalniku.
Naslednji koraki
Natančne sheme zahtev in odgovorov, vključno z vsakim konfiguracijskim ključem.
Enkrat pravilno nastavite HMAC; nato ga znova uporabite povsod.
Združite dinamično usmerjanje z orodji za posamezne agente.
Ponovni poskusi, vrstni red, časovne omejitve.