Open in
telephony.incoming / web.incoming
Blockerande webhook som formar konfigurationen för ett inkommande samtal i realtid.
När ett inkommande telefonsamtal når ett nummer utan en tilldelad
röstagent, eller när en webbwidgets-session startar med en publicerbar nyckel i
mode="webhook", skickar ThunderPhone en blockerande
telephony.incoming / web.incoming-begäran till din
äldre webhook-URL
och väntar på ett konfigurationssvar: upp till 13 sekunder för ett
telefonsamtal, inklusive ett återförsök, och upp till 10 sekunder för en
widgetsession (se Timeouter och återförsök). Använd detta
utbyte för att dynamiskt välja en prompt, röst och verktyg per samtal —
se guiden för dynamisk samtalskonfiguration
för flödet från början till slut.
Tidsgränser och återförsök
Svara snabbt: uppringaren väntar kvar i samtalet medan du bestämmer dig.
För ett telefonsamtal (telephony.incoming):
- Det första försöket kan ta upp till 10 sekunder.
- Om det får en timeout, inte kan ansluta eller får ett svar med
5xx,408eller429försöker ThunderPhone en gång till. Återförsöket får det som återstår av en budget på 13 sekunder för hela utbytet: cirka 3 sekunder efter ett första försök som fick timeout, nästan alla 13 efter ett snabbt fel. Inget återförsök görs när mindre än 2 sekunder skulle återstå. - Alla andra
4xx-svar, ett svar över storleksgränsen eller ett2xxvars brödtext inte är en giltig konfiguration är slutgiltiga och försöks inte igen. - Båda försöken skickar samma brödtext, samma
X-ThunderPhone-Signatureoch sammaX-ThunderPhone-Idempotency-Key-header (telephony-incoming-<call_id>), så att en hanterare med sidoeffekter kan känna igen återförsöket.
Det finns ingen reservröstagent. Om ingen användbar konfiguration kommer fram avslutas samtalet direkt i stället för att låta uppringaren vänta i en tyst linje. Det visas i samtalshistoriken som ett misslyckat, ej debiterat samtal med end_reason inbound_config_webhook_failed, och det vanliga telephony.complete-eventet skickas.
En widgetsessions (web.incoming) får ett enda försök på upp till 10 sekunder. Om det misslyckas misslyckas sessionsbegäran med 502 eller 422.
Begärans nyttolast
För telefonsamtal (telephony.incoming):
{
"type": "telephony.incoming",
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}| Fält | Typ | Beskrivning |
|---|---|---|
call_id | integer | Samtals-ID — stabilt i alla händelser för detta samtal |
from_number | string | E.164-nummer för den som ringer |
to_number | string | E.164-destination (ett av dina ThunderPhone-nummer) |
För webbsessioner i webbwidgeten (web.incoming) identifierar data
inbäddningssidan i stället för telefonnummer:
{
"type": "web.incoming",
"data": {
"call_id": 987654322,
"origin_domain": "https://example.com",
"publishable_key_prefix": "pk_live_a1b2"
}
}| Fält | Typ | Beskrivning |
|---|---|---|
call_id | heltal | Samtals-id |
origin_domain | sträng | Sidans ursprung som är värd för widgeten, enligt vad webbläsaren skickade. En klient som inte är en webbläsare kan skicka vilket värde som helst, så behandla det inte som bevis på var begäran kom ifrån |
publishable_key_prefix | sträng | De första tecknen i den publicerbara nyckel som öppnade sessionen |
language, primary_language | sträng | Finns när widgetsessionen begärde en språköverstyrning |
voice | sträng | Finns när widgetsessionen begärde en röstöverstyrning |
website_context | sträng | Finns när widgeten skickade sidkontext per session |
Överstyrningsfälten (language, voice, website_context och eventuella
variables från webbläsaren) skickas endast när den publicerbara nyckeln tillåter dem i
sina webbläsaröverstyrningar. En
sessionsbegäran som innehåller en överstyrning som nyckeln inte tillåter avvisas innan
denna webhook anropas.
Svarsschema
Returnera ett JSON-objekt som beskriver agentkonfigurationen för det här samtalet.
prompt och voice krävs; allt annat är valfritt.
{
"prompt": "You are a helpful booking assistant for Acme Restaurant.",
"voice": "john",
"product": "spark",
"background_track": null,
"tools": []
}| Fält | Typ | Krävs | Beskrivning |
|---|---|---|---|
prompt | sträng | ja | Systemprompt som styr agenten |
voice | sträng | ja | Röst-id från GET /v1/voices, t.ex. john. voice_name accepteras som alias. Okända röster klarar inte valideringen och samtalet avvisas |
product | sträng | nej | Standardvärdet är spark. Tillåtna värden: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack |
thinking_level | sträng | nej | minimal, base (standard) eller extra. Åsidosätts för Storm-produkter: storm-extra* tvingar extra, andra storm-* tvingar base |
audio_context_mode | sträng | nej | full (standard) eller reduced |
watchdog_enabled | boolesk | nej | Aktivera övervakning för det här samtalet. Standardvärdet är false |
additional_audio_context | boolesk | null | nej | Inkludera de senaste turerna av uppringarens ljud i stället för bara den senaste turen, vilket förbättrar korrigeringar och insamling av uppgifter med mycket stavning eller siffror med en liten ökning av latens och kostnad. Är aktiverat som standard för inkommande sessioner och inaktiverat för utgående telefonsamtal; null behåller standardvärdet |
storm_feedback_mode | sträng | nej | none, acknowledgement (standard) eller tick. Anger även vad uppringaren hör medan ljudmodellerna bearbetar en tur när audio_tier är hearing |
language | sträng | nej | Förkortning för primary_language |
primary_language | sträng | nej | Språkkod, normaliserad (standardvärde en). Koder som inte kan lösas upp avvisar samtalet |
has_additional_languages | boolesk | nej | Standardvärdet är false |
additional_languages | matris av strängar | nej | Ytterligare språk som agenten kan växla till |
native_voice_switching | boolesk | nej | Standardvärdet är false. När samtalet växlar till ett annat språk byter du till en röst med det språket som modersmål (matchad efter kön) i stället för att behålla den konfigurerade rösten |
language_switching | sträng | null | nej | ask_first (standard) eller follow_caller; null är samma som ask_first. Anger hur en flerspråkig agent hanterar när den andra personen talar ett annat av agentens språk. ask_first växlar direkt när personen ber om språket eller säger en hel mening på det, och frågar om den ska fortsätta på språket efter något kort, som ett "ja". follow_caller växlar till vilket konfigurerat språk personen än talar, även vid ett enda ord. Gäller endast när additional_languages är angivet |
audio_tier | sträng | null | nej | Endast product: "bolt". standard (standard; "" och null betyder samma sak) kör tre transkriberare (samtal som behandlar PHI använder endast transkriberare som omfattas av BAA). lean sänker till en transkriberare, som hör fel oftare. hearing uppgraderar till standard plus en kraftfull ensemble av ljudmodeller som lyssnar på uppringarens ljud under vissa turer, vilka tar omkring 1–2 sekunder längre. Andra produkter ignorerar detta |
endpointing | sträng | null | nej | faster (200 ms), fast (300 ms), normal (500 ms, standard) eller patient (800 ms); null är samma som normal. Anger hur länge en Bolt v2-agent väntar efter att uppringaren slutat tala innan modellen ombeds om ett svar. Kortare väntetider kan svara tidigare men skickar fler begäranden som uppringarens nästa ord gör inaktuella, vilket ökar modellkostnaden. Andra produkter ignorerar detta |
eagerness | sträng | null | nej | Föråldrat: namnet på endpointing fram till den 19 oktober 2026, läses fortfarande. Ignoreras när endpointing är angivet |
intelligence | sträng | null | nej | express, lite eller standard (standard); null är samma som standard. Intelligensnivån för en bolt-agent i Bolt v2-pipelinen: vilken modell som skriver dess svar. express är ~600 ms till första ordet, billigare än Standard och följer instruktioner minst tillförlitligt; lite är ~900 ms, billigast och mindre tillförlitlig; standard är ~900 ms och bäst på att följa instruktioner. Express- och Lite-svar som bara skulle anropa ett verktyg skickas till Standard-modellen. Andra produkter ignorerar detta |
background_track | sträng | null | nej | Id för bakgrundsljud eller null |
acknowledgement_prompt_mode | sträng | nej | auto (standard) eller manual (Storm-with-ack-produkter) |
acknowledgement_prompt | sträng | nej | Används när acknowledgement_prompt_mode="manual" |
silence_interval_seconds | heltal | null | nej | 5–120. Sekunder av tystnad från uppringaren före en avstämning |
silence_max_checkins | heltal | null | nej | 1–10 |
silence_checkins_enabled | boolesk | nej | Standardvärdet är true |
silence_final_action | sträng | nej | Efter den sista avstämningen: hang_up (standard) eller transfer till silence_transfer_destination |
silence_transfer_destination | sträng | nej | Namnet på en post i den här konfigurationens transfer_destinations; krävs med transfer. Utan transfer_destinations kan överföringen inte genomföras och agenten lägger på |
silence_final_message | sträng | nej | ≤ 300 tecken, läses upp som skrivet; "" (standard) använder standardraden |
connect_tone_enabled | boolesk | nej | Standardvärdet är false |
pronunciation_dicts | boolesk | null | nej | Standardvärdet är false; null är samma som false. När värdet är true använder samtalets Cartesia-tal ThunderPhones uttalslexikon för samtalets språk, där ett finns. Fungerar för telefon- och widget-samtal. Gäller endast ThunderPhones egna Cartesia-röster, inte röster på din egen Cartesia API-nyckel. Används inte med agent_id, där den sparade agentens inställningar gäller |
voicemail_action | sträng | nej | prompt (standard), hangup eller message |
voicemail_message | sträng | nej | Används när voicemail_action="message" |
agent_name | sträng | nej | Visningsnamn som rapporteras till instrumentpaneler och widgeten |
org_name | sträng | nej | Organisationens visningsnamn för agentens persona |
tools | matris | nej | Infogade scheman för funktionsverktyg (se Funktionsverktyg) |
transfer_destinations | matris av objekt | null | nej | Upp till 50 poster med {name, number} som det här samtalet kan överföras till, validerade som en agents överföringsnummer. Agenten överför efter namn och endast till dessa; [] betyder inga överföringar. Utelämna det eller skicka null för att låta agenten överföra till ett nummer som den väljer |
timezone | sträng | nej | IANA-tidszon för det här samtalet, till exempel America/Chicago. Agenten anger datum och tid i den, före agentens egen tidszon. Tillåts även tillsammans med agent_id. Värden som inte är IANA-zoner ignoreras. Se Ange tidszonen per samtal |
call_id | heltal | nej | Valfritt eko av begärans samtals-id; ignoreras |
Eftersom prompt och voice krävs avvisas samtalet om du returnerar {} eller ett
svar som inte klarar valideringen: ett telefonsamtal avslutas enligt beskrivningen i
Timeouts och återförsök, och en begäran om en widgetsession misslyckas med 422. Det finns ingen reservlösning med statisk agent
på den här vägen (ett nummer eller en nyckel i webhook-läge har ingen tilldelad
agent).
Begränsning av svarsstorlek
Exempel på hanterare
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 funktionsverktyg
Koppla verktyg så att AI:n kan anropa dina API:er mitt i samtalet:
{
"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"
}
}
}
]
}Snabbguide till produktnivåer
| Produkt | Latens | Resonemang | Bekräftelse |
|---|---|---|---|
spark | Lägst | Grundläggande | — |
bolt | Låg | Förbättrat | — |
storm-base | Medel | Starkt | — |
storm-base-with-ack | Medel | Starkt | Automatisk utfyllnad medan den tänker |
storm-extra | Högre | Djupgående | — |
storm-extra-with-ack | Högre | Djupgående | Automatisk utfyllnad medan den tänker |
Relaterat
Den icke-blockerande händelsen när samtalet avslutas.
Fullständigt JSON-schema för tools[] och det signerade endpoint-kontraktet.
Prenumerera med flera URL:er på telephony.incoming / web.incoming.
Mönster för prompts, verktyg och A/B-tester per uppringare.