ThunderPhone 2.0 yayında.Hemen kendiniz kullanmaya başlayın; dakikası 2 sentten başlayan fiyatlarla.Duyuruyu okuyun

Webhooks

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, 408 ya da 429 yanı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 4xx yanıtları, boyut sınırını aşan yanıtlar veya gövdesi geçerli bir yapılandırma olmayan 2xx yanıtları kesindir ve yeniden denenmez.
  • Her iki deneme de aynı gövdeyi, aynı X-ThunderPhone-Signature ve 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"
  }
}
AlanTürAçıklama
call_idintegerÇağrı kimliği — bu çağrıdaki tüm olaylarda sabittir
from_numberstringE.164 arayan numarası
to_numberstringE.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"
  }
}
AlanTürAçıklama
call_idintegerArama kimliği
origin_domainstringTarayı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_prefixstringOturumu açan yayımlanabilir anahtarın ilk karakterleri
language, primary_languagestringWidget oturumu bir dil geçersiz kılması istediğinde bulunur
voicestringWidget oturumu bir ses geçersiz kılması istediğinde bulunur
website_contextstringWidget 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":   []
}
AlanTürZorunluAçıklama
promptstringevetAjanı yönlendiren sistem istemi
voicestringevetGET /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
productstringhayırVarsayılan değer spark olur. İzin verilenler: spark, bolt, storm-base, storm-base-with-ack, storm-extra, storm-extra-with-ack
thinking_levelstringhayırminimal, 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_modestringhayırfull (varsayılan) veya reduced
watchdog_enabledbooleanhayırBu çağrı için denetimi etkinleştirin. Varsayılan değer false
additional_audio_contextboolean | nullhayırYalnı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_modestringhayırnone, acknowledgement (varsayılan) veya tick
languagestringhayırprimary_language için kısa ad
primary_languagestringhayırNormalleştirilmiş dil kodu (varsayılan en). Çözümlenemeyen kodlar çağrıyı reddeder
has_additional_languagesbooleanhayırVarsayılan değer false
additional_languagesarray of stringhayırAjanın geçiş yapabileceği ek diller
native_voice_switchingbooleanhayırVarsayı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_switchingstring | nullhayırask_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_trackstring | nullhayırOrtam sesi kimliği veya null
acknowledgement_prompt_modestringhayırauto (varsayılan) veya manual (Storm-with-ack ürünleri)
acknowledgement_promptstringhayıracknowledgement_prompt_mode="manual" olduğunda kullanılır
silence_interval_secondsinteger | nullhayır5–120. Bir kontrol mesajından önce arayanın sessiz kalacağı saniye sayısı
silence_max_checkinsinteger | nullhayır1–10
silence_checkins_enabledbooleanhayırVarsayılan değer true
connect_tone_enabledbooleanhayırVarsayılan değer false
pronunciation_dictsboolean | nullhayırVarsayı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_actionstringhayırprompt (varsayılan), hangup veya message
voicemail_messagestringhayırvoicemail_action="message" olduğunda kullanılır
agent_namestringhayırPanolara ve widget'a bildirilen görünen ad
org_namestringhayırAjanın kişiliği için kuruluş görünen adı
toolsarrayhayırSatır içi işlev aracı şemaları (bkz. İşlev Araçları)
transfer_destinationsarray of object | nullhayırBu ç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
timezonestringhayırBu ç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_idintegerhayı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

Python (FastAPI)
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 {}
Node.js (Express)
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ünGecikmeAkıl yürütmeOnay
sparkEn düşükTemel—
boltDüşükGelişmiş—
storm-baseOrtaGüçlü—
storm-base-with-ackOrtaGüçlüDüşünürken otomatik dolgu
storm-extraDaha yüksekDerin—
storm-extra-with-ackDaha yüksekDerinDüşünürken otomatik dolgu

İlgili