Open in
telephony.incoming / web.incoming
Blokerende webhook, der former konfigurationen for et indgående opkald i realtid.
Når et indgående telefonopkald når et nummer uden en tilknyttet
agent, eller en webwidgetsession starter på en publicerbar nøgle i
mode="webhook", sender ThunderPhone en blokerende
telephony.incoming / web.incoming-anmodning til din
ældre webhook-URL
og venter på et konfigurationssvar: op til 13 sekunder for et
telefonopkald, inklusive ét genforsøg, og op til 10 sekunder for en
widgetsession (se Timeouts and retries). Brug denne
udveksling til dynamisk at vælge en prompt, stemme og værktøjer pr. opkald —
se vejledningen til dynamisk opkaldskonfiguration
for det fulde mønster.
Tidsgrænser og genforsøg
Svar hurtigt: Personen, der ringer, venter på linjen, mens du beslutter dig.
For et telefonopkald (telephony.incoming):
- Det første forsøg kan tage op til 10 sekunder.
- Hvis det får timeout, ikke kan oprette forbindelse eller modtager et
5xx-,408- eller429-svar, prøver ThunderPhone én gang til. Genforsøget får den resterende tid af et budget på 13 sekunder for hele udvekslingen: omkring 3 sekunder efter et første forsøg med timeout, næsten alle 13 efter en hurtig fejl. Der foretages ikke noget genforsøg, hvis der ville være mindre end 2 sekunder tilbage. - Ethvert andet
4xx-svar, et svar over størrelsesgrænsen eller et2xx-svar, hvis brødtekst ikke er en gyldig konfiguration, er endeligt og prøves ikke igen. - Begge forsøg sender den samme brødtekst, den samme
X-ThunderPhone-Signatureog den sammeX-ThunderPhone-Idempotency-Key-header (telephony-incoming-<call_id>), så en handler med bivirkninger kan genkende genforsøget.
Der er ingen fallback-agent. Hvis der ikke modtages en brugbar konfiguration, afsluttes
opkaldet straks i stedet for at lade personen, der ringer, vente på en stille
linje. Det vises i opkaldshistorikken som et mislykket, ikke-faktureret opkald med
end_reason inbound_config_webhook_failed, og det sædvanlige
telephony.complete-event sendes.
En widgetsession (web.incoming) får ét forsøg på op til 10
sekunder. Hvis det mislykkes, mislykkes sessionsanmodningen med 502 eller 422.
Anmodningspayload
For telefonopkald (telephony.incoming):
{
"type": "telephony.incoming",
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}| Felt | Type | Beskrivelse |
|---|---|---|
call_id | integer | Opkalds-id — stabilt på tværs af alle hændelser for dette opkald |
from_number | string | Opkaldernummer i E.164-format |
to_number | string | Destination i E.164-format (et af dine ThunderPhone-numre) |
For webwidgetsessioner (web.incoming) identificerer data
indlejringssiden i stedet for telefonnumre:
{
"type": "web.incoming",
"data": {
"call_id": 987654322,
"origin_domain": "https://example.com",
"publishable_key_prefix": "pk_live_a1b2"
}
}| Felt | Type | Beskrivelse |
|---|---|---|
call_id | integer | Opkalds-id |
origin_domain | string | Sidens oprindelse, der hoster widgetten, som browseren sendte den. En klient, der ikke er en browser, kan sende en vilkårlig værdi, så betragt den ikke som bevis på, hvor anmodningen kom fra |
publishable_key_prefix | string | Første tegn i den publicerbare nøgle, der åbnede sessionen |
language, primary_language | string | Findes, når widgetsessionen har anmodet om en sprogtilsidesættelse |
voice | string | Findes, når widgetsessionen har anmodet om en stemmetilsidesættelse |
website_context | string | Findes, når widgetten har sendt sidekontekst pr. session |
Tilsidesættelsesfelterne (language, voice, website_context og eventuelle
browser-variables) ankommer kun, når den publicerbare nøgle tillader dem i
sine browsertilsidesættelser. En
sessionsanmodning med en tilsidesættelse, som nøglen ikke tillader, afvises,
før denne webhook kaldes.
Svarskema
Returner et JSON-objekt, der beskriver agentkonfigurationen for dette opkald.
prompt og voice er påkrævede; alt andet er valgfrit.
{
"prompt": "You are a helpful booking assistant for Acme Restaurant.",
"voice": "john",
"product": "spark",
"background_track": null,
"tools": []
}| Felt | Type | Påkrævet | Beskrivelse |
|---|---|---|---|
prompt | streng | ja | Systemprompt, der styrer agenten |
voice | streng | ja | Stemme-id fra GET /v1/voices, f.eks. john. voice_name accepteres som et alias. Ukendte stemmer fejler validering og afviser opkaldet |
product | streng | nej | Standard er spark. Tilladt: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack |
thinking_level | streng | nej | minimal, base (standard) eller extra. Tilsidesættes for Storm-produkter: storm-extra* tvinger extra, andre storm-* tvinger base |
audio_context_mode | streng | nej | full (standard) eller reduced |
watchdog_enabled | boolesk | nej | Aktivér overvågning for dette opkald. Standard er false |
additional_audio_context | boolesk | null | nej | Medtag de seneste par runder af opkalderens lyd i stedet for kun den seneste runde, hvilket forbedrer rettelser og indsamling af data med mange stavemåder eller tal med en lille meromkostning i latenstid og pris. Er som standard slået til for indgående sessioner og slået fra for udgående telefonopkald; null bevarer standardindstillingen |
storm_feedback_mode | streng | nej | none, acknowledgement (standard) eller tick. Angiver også, hvad opkalderen hører, mens lydmodellerne behandler en runde, når audio_tier er hearing |
language | streng | nej | Forkortelse for primary_language |
primary_language | streng | nej | Sprogkode, normaliseret (standard er en). Koder, der ikke kan fortolkes, afviser opkaldet |
has_additional_languages | boolesk | nej | Standard er false |
additional_languages | array af strenge | nej | Ekstra sprog, som agenten kan skifte til |
native_voice_switching | boolesk | nej | Standard er false. Når opkaldet skifter til et andet sprog, skal der skiftes til en stemme med det pågældende sprog som modersmål (matchet efter køn) i stedet for at beholde den konfigurerede stemme |
language_switching | streng | null | nej | ask_first (standard) eller follow_caller; null er det samme som ask_first. Angiver, hvordan en flersproget agent håndterer, at den anden person taler et andet af dens sprog. ask_first skifter straks, når personen beder om sproget eller siger en hel sætning på det, og spørger, om samtalen skal fortsætte på det efter noget kort, som et "ja". follow_caller skifter til ethvert konfigureret sprog, personen taler, selv ved et enkelt ord. Gælder kun, når additional_languages er angivet |
audio_tier | streng | null | nej | Kun product: "bolt". standard (standard; "" og null betyder det samme) kører tre transskriberingsmodeller (opkald, der behandler PHI, bruger kun BAA-dækkede transskriberingsmodeller). lean nedgraderer til én transskriberingsmodel, som fejlhører oftere. hearing opgraderer til standard plus et kraftfuldt ensemble af lydmodeller, der lytter til opkalderens lyd i nogle runder, som tager ca. 1–2 sekunder længere. Andre produkter ignorerer det |
endpointing | streng | null | nej | faster (200 ms), fast (300 ms), normal (500 ms, standard) eller patient (800 ms); null er det samme som normal. Angiver, hvor længe en Bolt v2-agent venter, efter opkalderen stopper, før modellen bedes om et svar. Kortere ventetid kan svare hurtigere, men sender flere anmodninger, som opkalderens næste ord gør forældede, hvilket øger modelomkostningen. Andre produkter ignorerer det |
eagerness | streng | null | nej | Forældet: navnet på endpointing indtil 19. oktober 2026, læses stadig. Ignoreres, når endpointing er angivet |
intelligence | streng | null | nej | express, lite eller standard (standard); null er det samme som standard. Intelligensniveauet for en bolt-agent på Bolt v2-pipelinen: hvilken model der skriver dens svar. express bruger ca. 600 ms til første ord, er billigere end Standard og følger instruktioner mindst pålideligt; lite bruger ca. 900 ms, er billigst og mindre pålidelig; standard bruger ca. 900 ms og er bedst til at følge instruktioner. Express- og Lite-svar, der kun ville kalde et værktøj, sendes videre til Standard-modellen. Andre produkter ignorerer det |
background_track | streng | null | nej | Id for baggrundslyd eller null |
acknowledgement_prompt_mode | streng | nej | auto (standard) eller manual (Storm-with-ack-produkter) |
acknowledgement_prompt | streng | nej | Bruges, når acknowledgement_prompt_mode="manual" |
silence_interval_seconds | heltal | null | nej | 5–120. Sekunder med stilhed fra opkalderen før en opfølgning |
silence_max_checkins | heltal | null | nej | 1–10 |
silence_checkins_enabled | boolesk | nej | Standard er true |
silence_final_action | streng | nej | Efter den sidste opfølgning: hang_up (standard) eller transfer til silence_transfer_destination |
silence_transfer_destination | streng | nej | Navn på en post i denne konfigurations transfer_destinations; kræves med transfer. Uden transfer_destinations kan viderestillingen ikke gennemføres, og agenten lægger på |
silence_final_message | streng | nej | ≤ 300 tegn, læses op som skrevet; "" (standard) bruger standardlinjen |
connect_tone_enabled | boolesk | nej | Standard er false |
pronunciation_dicts | boolesk | null | nej | Standard er false; null er det samme som false. Når værdien er true, bruger opkaldets Cartesia-tale ThunderPhones udtaleordbog for opkaldets sprog, hvor en findes. Fungerer for telefon- og widgetopkald. Gælder kun ThunderPhones egne Cartesia-stemmer, ikke stemmer på din egen Cartesia API-nøgle. Bruges ikke med agent_id, hvor den gemte agents indstillinger gælder |
voicemail_action | streng | nej | prompt (standard), hangup eller message |
voicemail_message | streng | nej | Bruges, når voicemail_action="message" |
agent_name | streng | nej | Visningsnavn, der rapporteres til dashboards og widgetten |
org_name | streng | nej | Organisationens visningsnavn for agentens persona |
tools | array | nej | Integrerede skemaer for funktionsværktøjer (se Funktionsværktøjer) |
transfer_destinations | array af objekt | null | nej | Op til 50 poster med {name, number}, som dette opkald kan viderestilles til, valideret som en agents viderestillingsnumre. Agenten viderestiller efter navn og kun til disse; [] betyder ingen viderestillinger. Udelad feltet eller send null for at lade agenten viderestille til et nummer, den vælger |
timezone | streng | nej | IANA-tidszone for dette opkald, f.eks. America/Chicago. Agenten angiver dato og klokkeslæt i den frem for agentens egen tidszone. Tilladt også sammen med agent_id. Værdier, der ikke er IANA-zoner, ignoreres. Se Angiv tidszonen pr. opkald |
call_id | heltal | nej | Valgfrit ekko af anmodningens opkalds-id; ignoreres |
Da prompt og voice er påkrævet, afviser returnering af {} eller et
svar, der fejler valideringen, opkaldet: Et telefonopkald afsluttes
som beskrevet i Timeouts og genforsøg, og en
widget-sessionsforespørgsel fejler med 422. Der er ingen fallback til en
statisk agent på denne sti (et nummer eller en nøgle i webhook-tilstand har ingen tildelt
agent).
Grænse for svarstørrelse
Eksempel på handler
import hashlib
import hmac
import json
import os
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
WEBHOOK_SECRET = os.environ["THUNDERPHONE_WEBHOOK_SECRET"]
def verify(body: bytes, signature: str) -> bool:
expected = hmac.new(WEBHOOK_SECRET.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature or "")
@app.post("/thunderphone-webhook")
async def webhook(request: Request):
body = await request.body()
if not verify(body, request.headers.get("X-ThunderPhone-Signature", "")):
raise HTTPException(status_code=401)
event = json.loads(body)
if event["type"] == "telephony.incoming":
caller = event["data"]["from_number"]
prompt = (
"Greet the caller as a San Francisco local…"
if caller.startswith("+1415")
else "You are a friendly customer support agent…"
)
return {
"prompt": prompt,
"voice": "john",
"product": "spark",
}
if event["type"] == "web.incoming":
return {
"prompt": "You are the website's helpful voice assistant…",
"voice": "john",
"product": "spark",
}
return {}import crypto from "node:crypto";
import express from "express";
const app = express();
const SECRET = process.env.THUNDERPHONE_WEBHOOK_SECRET;
function verify(body, signature) {
const expected = crypto
.createHmac("sha256", SECRET)
.update(body)
.digest("hex");
return signature &&
crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(signature));
}
app.post(
"/thunderphone-webhook",
express.raw({ type: "application/json" }),
(req, res) => {
if (!verify(req.body, req.header("X-ThunderPhone-Signature"))) {
return res.sendStatus(401);
}
const event = JSON.parse(req.body.toString("utf8"));
if (event.type === "telephony.incoming" || event.type === "web.incoming") {
const caller = event.data.from_number || "web";
const prompt = caller.startsWith("+1415")
? "Greet the caller as a San Francisco local…"
: "You are a friendly customer support agent…";
return res.json({
prompt,
voice: "john",
product: "spark",
});
}
res.json({});
},
);Svar med funktionsværktøjer
Tilknyt værktøjer, så AI'en kan kalde dine API'er midt i samtalen:
{
"prompt": "You are a booking assistant. Use the available tools to help customers schedule appointments.",
"voice": "john",
"product": "spark",
"tools": [
{
"type": "function",
"function": {
"name": "search_appointments",
"description": "Find available appointment slots",
"parameters": {
"type": "object",
"properties": {
"date": { "type": "string", "description": "YYYY-MM-DD" },
"service": { "type": "string" }
},
"required": ["date"]
}
},
"endpoint": {
"url": "https://api.example.com/appointments/search",
"method": "POST",
"headers": {
"X-Api-Key": "your-key"
}
}
}
]
}Produktniveauer – hurtig oversigt
| Produkt | Latens | Ræsonnering | Bekræftelse |
|---|---|---|---|
spark | Lavest | Grundlæggende | — |
bolt | Lav | Forbedret | — |
storm-base | Mellem | Stærk | — |
storm-base-with-ack | Mellem | Stærk | Automatisk udfyldning, mens der tænkes |
storm-extra | Højere | Dyb | — |
storm-extra-with-ack | Højere | Dyb | Automatisk udfyldning, mens der tænkes |
Relateret
Den ikke-blokerende hændelse ved opkaldets afslutning.
Fuld JSON-schema for tools[] og den signerede endpoint-kontrakt.
Abonner flere URL'er på telephony.incoming / web.incoming.
Mønstre til prompts, værktøjer og A/B-tests pr. opkalder.