Open in
telephony.incoming / web.incoming
Gelen bir aramanın yapılandırmasını gerçek zamanlı olarak şekillendiren engelleyici webhook.
Bir gelen telefon araması atanmış bir yapay zeka ajanı
olmayan bir numaraya ulaştığında veya bir web widget oturumu
mode="webhook" içindeki yayımlanabilir bir anahtarda başladığında, ThunderPhone
eski webhook URL'nize
engelleyici bir telephony.incoming / web.incoming isteği gönderir
ve yapılandırma yanıtını bekler: telefon araması için, bir yeniden deneme
dahil, en fazla 13 saniye; widget oturumu için ise en fazla 10 saniye
(Zaman aşımları ve yeniden denemeler bölümüne bakın). Bu
alışverişi kullanarak her arama için istemi, sesi ve araçları dinamik olarak seçin —
uçtan uca akış için dinamik arama yapılandırma kılavuzuna
bakın.
Zaman aşımları ve yeniden denemeler
Hızlı yanıt verin: siz karar verirken arayan kişi hatta bekliyor.
Bir telefon görüşmesi (telephony.incoming) için:
- İlk deneme 10 saniyeye kadar sürebilir.
- Zaman aşımına uğrarsa, bağlanamazsa veya
5xx,408ya da429yanıtı alırsa ThunderPhone bir kez daha dener. Yeniden deneme, tüm alışveriş için ayrılan 13 saniyelik bütçeden kalan süreyi kullanır: zaman aşımına uğrayan ilk denemeden sonra yaklaşık 3 saniye, hızlı bir hatadan sonra ise neredeyse 13 saniyenin tamamı. 2 saniyeden az süre kalacaksa yeniden deneme yapılmaz. - Diğer tüm
4xxyanıtları, boyut sınırını aşan yanıtlar veya gövdesi geçerli bir yapılandırma olmayan2xxyanıtları kesindir ve yeniden denenmez. - Her iki deneme de aynı gövdeyi, aynı
X-ThunderPhone-Signatureve aynıX-ThunderPhone-Idempotency-Keyüst bilgisini (telephony-incoming-<call_id>) gönderir; böylece yan etkileri olan bir işleyici yeniden denemeyi tanıyabilir.
Yedek yapay zeka ajanı yoktur. Kullanılabilir bir yapılandırma gelmezse,
arayan kişiyi sessiz bir hatta bekletmek yerine görüşme hemen sonlandırılır.
Çağrı geçmişinde end_reason değeri inbound_config_webhook_failed olan
başarısız, ücretlendirilmeyen bir çağrı olarak görünür ve standart
telephony.complete olayı gönderilir.
Bir widget oturumu (web.incoming), 10 saniyeye kadar tek bir deneme alır.
Başarısız olursa oturum isteği 502 veya 422 ile başarısız olur.
İstek yükü
Telefon çağrıları için (telephony.incoming):
{
"type": "telephony.incoming",
"data": {
"call_id": 987654321,
"from_number": "+14155550199",
"to_number": "+15551234567"
}
}| Alan | Tür | Açıklama |
|---|---|---|
call_id | integer | Çağrı kimliği — bu çağrıdaki tüm olaylarda sabittir |
from_number | string | E.164 arayan numarası |
to_number | string | E.164 hedefi (ThunderPhone numaralarınızdan biri) |
Web bileşeni oturumları için (web.incoming) data, telefon
numaraları yerine yerleştirme sayfasını tanımlar:
{
"type": "web.incoming",
"data": {
"call_id": 987654322,
"origin_domain": "https://example.com",
"publishable_key_prefix": "pk_live_a1b2"
}
}| Alan | Tür | Açıklama |
|---|---|---|
call_id | integer | Arama kimliği |
origin_domain | string | Tarayıcının gönderdiği şekilde widget'ı barındıran sayfanın kaynağı. Tarayıcı dışı bir istemci herhangi bir değer gönderebileceğinden, bunu isteğin geldiği yerin kanıtı olarak kabul etmeyin |
publishable_key_prefix | string | Oturumu açan yayımlanabilir anahtarın ilk karakterleri |
language, primary_language | string | Widget oturumu bir dil geçersiz kılması istediğinde bulunur |
voice | string | Widget oturumu bir ses geçersiz kılması istediğinde bulunur |
website_context | string | Widget oturum başına sayfa bağlamı ilettiğinde bulunur |
Geçersiz kılma alanları (language, voice, website_context ve tüm
tarayıcı variables değerleri), yalnızca yayımlanabilir anahtar bunlara
tarayıcı geçersiz kılmalarında izin verdiğinde gelir. Anahtarın izin vermediği bir alanı içeren oturum isteği,
bu webhook çağrılmadan önce reddedilir.
Yanıt şeması
Bu çağrı için ajan yapılandırmasını açıklayan bir JSON nesnesi döndürün.
prompt ve voice zorunludur; diğer her şey isteğe bağlıdır.
{
"prompt": "You are a helpful booking assistant for Acme Restaurant.",
"voice": "john",
"product": "spark",
"background_track": null,
"tools": []
}| Alan | Tür | Zorunlu | Açıklama |
|---|---|---|---|
prompt | string | evet | Ajanı yönlendiren sistem istemi |
voice | string | evet | GET /v1/voices içindeki ses kimliği; örneğin john. voice_name diğer ad olarak kabul edilir. Bilinmeyen sesler doğrulamadan geçemez ve çağrı reddedilir |
product | string | hayır | Varsayılan değer spark olur. İzin verilenler: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack |
thinking_level | string | hayır | minimal, base (varsayılan) veya extra. Storm ürünleri için geçersiz kılınır: storm-extra*, extra değerini zorunlu kılar; diğer storm-* ürünleri base değerini zorunlu kılar |
audio_context_mode | string | hayır | full (varsayılan) veya reduced |
watchdog_enabled | boolean | hayır | Bu çağrı için denetimi etkinleştirin. Varsayılan değer false |
additional_audio_context | boolean | null | hayır | Yalnızca en son tur yerine arayanın sesinin son birkaç turunu dahil ederek, küçük bir gecikme/maliyet artışı karşılığında düzeltmeleri ve yazım/sayı ağırlıklı veri toplamayı iyileştirin. Gelen oturumlarda varsayılan olarak açıktır, giden telefon çağrılarında kapalıdır; null varsayılanı korur |
storm_feedback_mode | string | hayır | none, acknowledgement (varsayılan) veya tick |
language | string | hayır | primary_language için kısa ad |
primary_language | string | hayır | Normalleştirilmiş dil kodu (varsayılan en). Çözümlenemeyen kodlar çağrıyı reddeder |
has_additional_languages | boolean | hayır | Varsayılan değer false |
additional_languages | array of string | hayır | Ajanın geçiş yapabileceği ek diller |
native_voice_switching | boolean | hayır | Varsayılan değer false. Çağrı başka bir dile geçtiğinde, yapılandırılmış sesi korumak yerine o dile özgü bir sesle değiştirin (cinsiyete göre eşleştirilir) |
language_switching | string | null | hayır | ask_first (varsayılan) veya follow_caller; null, ask_first ile aynıdır. Çok dilli bir ajanın, diğer kişinin kendi dillerinden başka birini konuşmasını nasıl ele aldığını belirler. ask_first, kişi dili istediğinde veya o dilde tam bir cümle söylediğinde hemen geçiş yapar; "evet" gibi kısa bir şeyden sonra ise o dilde devam edilip edilmeyeceğini sorar. follow_caller, tek bir kelime bile olsa konuşulan yapılandırılmış dile geçiş yapar. Yalnızca additional_languages ayarlandığında uygulanır |
background_track | string | null | hayır | Ortam sesi kimliği veya null |
acknowledgement_prompt_mode | string | hayır | auto (varsayılan) veya manual (Storm-with-ack ürünleri) |
acknowledgement_prompt | string | hayır | acknowledgement_prompt_mode="manual" olduğunda kullanılır |
silence_interval_seconds | integer | null | hayır | 5–120. Bir kontrol mesajından önce arayanın sessiz kalacağı saniye sayısı |
silence_max_checkins | integer | null | hayır | 1–10 |
silence_checkins_enabled | boolean | hayır | Varsayılan değer true |
connect_tone_enabled | boolean | hayır | Varsayılan değer false |
pronunciation_dicts | boolean | null | hayır | Varsayılan değer false; null, false ile aynıdır. true olduğunda, çağrının Cartesia konuşması, mevcutsa çağrının dili için ThunderPhone'un telaffuz sözlüğünü kullanır. Telefon ve widget çağrılarında çalışır. Yalnızca ThunderPhone'un kendi Cartesia sesleri için geçerlidir; kendi Cartesia API anahtarınızdaki sesler için geçerli değildir. Kaydedilmiş ajanın ayarlarının uygulandığı agent_id ile kullanılmaz |
voicemail_action | string | hayır | prompt (varsayılan), hangup veya message |
voicemail_message | string | hayır | voicemail_action="message" olduğunda kullanılır |
agent_name | string | hayır | Panolara ve widget'a bildirilen görünen ad |
org_name | string | hayır | Ajanın kişiliği için kuruluş görünen adı |
tools | array | hayır | Satır içi işlev aracı şemaları (bkz. İşlev Araçları) |
transfer_destinations | array of object | null | hayır | Bu çağrının aktarabileceği en fazla 50 {name, number} girişi; bir ajanın aktarım numaraları gibi doğrulanır. Ajan ada göre ve yalnızca bunlara aktarım yapar; [], aktarım olmadığı anlamına gelir. Ajanın seçtiği bir numaraya aktarım yapmasına izin vermek için bunu atlayın veya null gönderin |
timezone | string | hayır | Bu çağrı için America/Chicago gibi IANA saat dilimi. Ajan, kendi saat diliminden önce bu saat dilimindeki tarihi ve saati belirtir. agent_id yanında da izin verilir. IANA saat dilimi olmayan değerler yok sayılır. Bkz. Çağrı başına saat dilimini ayarlama |
call_id | integer | hayır | İsteğin çağrı kimliğinin isteğe bağlı yankısı; yok sayılır |
prompt ve voice zorunlu olduğundan, {} döndürmek veya doğrulamadan geçemeyen herhangi bir yanıt aramayı reddeder: telefon araması Zaman aşımları ve yeniden denemeler bölümünde açıklandığı şekilde sonlandırılır ve bileşen oturumu isteği 422 ile başarısız olur. Bu yolda statik ajan geri dönüşü yoktur (webhook modundaki bir numaraya veya anahtara atanmış bir ajan bulunmaz).
Yanıt boyutu sınırı
Örnek işleyici
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({});
},
);İşlev araçlarıyla yanıt
Yapay zekanın görüşme sırasında API'lerinizi çağırabilmesi için araçlar ekleyin:
{
"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"
}
}
}
]
}Ürün katmanı hızlı başvuru
| Ürün | Gecikme | Akıl yürütme | Onay |
|---|---|---|---|
spark | En düşük | Temel | — |
bolt | Düşük | Gelişmiş | — |
storm-base | Orta | Güçlü | — |
storm-base-with-ack | Orta | Güçlü | Düşünürken otomatik dolgu |
storm-extra | Daha yüksek | Derin | — |
storm-extra-with-ack | Daha yüksek | Derin | Düşünürken otomatik dolgu |
İlgili
Engellemeyen çağrı sonu olayı.
tools[] için tam JSON şeması ve imzalı uç nokta sözleşmesi.
Birden çok URL'yi telephony.incoming / web.incoming olaylarına abone edin.
Arayana özel istemler, araçlar ve A/B testleri için kalıplar.